太複雜了,一定會忘記
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&
}
 
沒有留言:
張貼留言