2012-07-13 61 views
16
#include <iostream> 
#include <type_traits> 

double f(int i) 
{ 
     return i+0.1; 
} 

struct F 
{ 
     public: 
     double operator()(int i) { return i+0.1; } 
}; 

int 
main(int, char**) 
{ 
     std::result_of<F(int)>::type x;  // ok 
     // std::result_of<f(int)>::type x; // error: template argument 1 is invalid 
     x = 0.1; 
     std::cerr << x << std::endl; 
} 

請解釋爲什麼std::result_of<f(int)>::type x;無效...的std ::的result_of簡單的功能

cppreference說: 「(std::result_of)推導出在編譯類型的函數調用表達式的返回類型。」

有什麼問題?

+3

的解決方案是使用本'的std ::的result_of :: type x;'。如果您想深入瞭解,請查看http://stackoverflow.com/q/2763824/893693 – inf 2012-07-13 13:22:51

回答

22

std::result_of<T>要求T是一種類型 - 但不只是任何類型。 T必須是一個函數式所以result_of這部分特將被使用:

template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>; 

使得:

decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...)) 

是公形成(C++ 11 20.9.7.6) 。 (INVOKE在20.8.2中定義)

原因std::result_of<f(int)>不起作用是因爲f不是類型 - 它是函數類型的一個實例。要聲明x是應用於intf返回類型,簡單地寫:

decltype(f(int{})) x; 

或者如果你喜歡硬編碼的int

decltype(f(32)) x; 

如果類型f然後用:

using FuncPtr = decltype(f); 

在所提供的代碼F(即,不小寫f)然而是一種類型的,因此F(int)限定了代表返回F受理int爲參數的函數的類型。顯然這不是F的意思! F的類型是一個結構,它的實例可以使用函數調用操作符。 F也沒有明確或隱含的構造函數,也可以使用int等。這如何工作?簡短的回答:模板「魔術」。

本質上,std::result_of的定義採用類型F(int)並將返回類型與參數類型分開,以便確定哪種情況的INVOKE()可以使其工作。 INVOKE的情況是:

  1. F是一個指針,指向用於一些T級
  2. 一個成員函數如果只有一個參數,F是一個指針,指向類T的數據成員,或者,
  3. 一架F的實例可以作爲一個功能,即,
declval<F>()(declval<int>()) 

它可以是一個普通的函數調用或某些類型的函子(例如,像您的例子)。

一旦確定result_of可以確定有效表達式的返回類型。這是通過result_oftype成員返回的內容。

關於這件事的美妙之處在於,result_of的用戶不需要知道任何有關這個實際工作方式的信息。唯一需要了解的是result_of需要一個函數TYPE。如果使用的是代碼中不是類型的名稱(例如,f),則需要使用decltype來獲取具有這種類型的表達式的類型。

最後,爲什麼f不能被視爲一個類型的部分原因是模板參數也允許常量值,而f是一個常量函數指針值。這是很容易證明(使用f問題的定義):

template <double Op(int)> 
double invoke_op(int i) 
{ 
    return Op(i); 
} 

及更高版本:

std::cout << invoke_op<f>(10) << std::endl; 

因此,要獲得正確調用f一些int表達式的返回值的類型一會寫:

decltype(f(int{})) 

(注:f不會被調用:編譯器簡單地使用內decltype表達以確定其結果即在這種情況下它的返回值。)