2012-07-13 7 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 :: xを入力します。より深い理解が必要な場合は、この質問をチェックしてください。http://stackoverflow.com/q/2763824/893693 – inf

答えて

22

std::result_of<T>は、タイプにかかわらず、Tが必要です。

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

ように:Tresult_ofのこの部分的な特殊化が使用されるように関数型である必要があり

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

がよく形成されている(C++ 11 20.9.7.6) 。 (INVOKEは20.8.2で定義されています)

std::result_of<f(int)>が機能しないのは、fがタイプではないからです。これは、関数型のインスタンスです。タイプした場合

decltype(f(32)) x; 

decltype(f(int{})) x; 

か、ハードコーディングintを好む場合:intに適用fの戻り値の型であることをxを宣言するには、単にこれを書きますfが望ましい場合は、次を使用します。

提供されるコード F(すなわち、低くない場合 f)0
using FuncPtr = decltype(f); 

しかしタイプなどF(int)ある引数としてintを受け入れるFを返す関数を表すタイプを定義します。明らかにこれはFのものではありません! Fの型は、インスタンスが関数呼び出し演算子を使用できる構造体です。 Fには、intなどを取る明示的または暗黙的なコンストラクタもありません。これはどのように機能しますか?短い答え:テンプレート "魔法"。

本質的に、std::result_ofの定義では、タイプがF(int)で、戻り値の型を引数の型から切り離して、INVOKE()がどのような場合に動作するかを判断できるようにします。 INVOKEの場合は、次のとおり

  1. Fは、唯一の引数がある場合、Fは、クラスTのデータメンバへのポインタであるか、または、
  2. いくつかのクラスT
  3. ためのメンバ関数へのポインタでありますFの
  4. インスタンスは、すなわち関数として使用することができ、通常の関数呼び出しまたは(例えば、あなたの例のように)ファンクターのいくつかのタイプにすることができ
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 1つは書くでしょう:

decltype(f(int{})) 

(注:fが呼び出されることはありません:コンパイラは、単純にその結果を決定するためにdecltype内の式を使用していますつまり、この場合には、その戻り値。)

関連する問題