太複雜了,一定會忘記
C++ 總共有三種 Type Deduction
I. template argument deduction
template < typename T >
void f(ParamType param);
f(expr); // 從 expr 推導 T 跟 Param
template argument deduction 有三種 case
1. ParamType 是 pointer 或 ref,但不是 universal ref
- 如果 expr 是 ref,把 ref 拿掉
- pattern-match,導出 T 跟 ParamType
2. ParamType 是 universal ref(就是有 && 的形式)
- 如果 expr 是 lvalue,那 T 跟 ParamType 都導成 lvalue ref
- 如果 expr 是 rvalue,那就跟平常一樣(平常一樣是啥?)
3. ParamType 不是 pointer 也不是 ref
- 如果 expr 是 ref,把 ref 拿掉
- ref 拿掉之後,如果 expr 是 const/volatile,也拿掉
另外,array 跟 function 會退化成 pointer
II. auto deduction
跟 template argument deduction 幾乎一樣,除了初始化的時候對待 {...} 不一樣, auto 會把 {...} 推導成 std::initializer_list ,但 template argument 無法推導 {...}
auto a = {1, 2, 3}; // a 是 std::initializer_list
f({1, 2, 3}); // 編譯失敗,無法推導 T
III. decltype deduction
什麼就是什麼
const int a = 7; // decltype(a) 就是 const int
const int& b = a; // decltype(b) 就是 const int&
decltype 最常用來作的,就是用來傳遞「原原本本的型態」,比方說你有一個 wrapper function,需要 perfect forward,然後 return value 的型別也要一五一十的反應出來,那你的好朋友就是 decltype 。
template < typename F, typename ... Args >
auto func_timer(F&& f, Args&& ... args)
-> decltype(f(std::forward(args)...))
{
auto begin = time();
decltype(f(std::forward(args)...)) result = f(std::forward(args)...);
std::cout << time() - begin << std::endl;
return result;
}
func_timer(foo, 1, 2, 3);
因為 foo 的 return value 有可能是 reference,人家有可能寫
func_timer(foo, 1, 2, 3) = bar;
所以連 referenceness 也要保留,所以要用 decltype 。但那一大長串實在太麻煩,所以 C++14 提供 decltype(auto) ,讓你可以簡單
template < typename F, typename ... Args >
decltype(auto) func_timer(F&& f, Args&& ... args) {
auto begin = time();
decltype(auto) result = f(std::forward(args)...);
std::cout << time() - begin << std::endl;
return result;
}
喔,使用 decltype(auto) 的時候還有一個特例要記住。 decltype(auto) 有兩條規則:
1. 如果遇到單單一個 name 的 lvalue expression, decltype(auto) 就是那個 name 的型別
2. 如果不是單單一個 name 的 lvalue expression, decltype(auto) 帶有 ref
decltype(auto) f1() {
int x = 0;
return x; // decltype(auto) 是 int,所以 f() 也是 int
}
decltype(auto) f1() {
int x = 0;
return (x); // decltype(auto) 是 int&,所以 f() 也是 int&
}