2012-08-17 10 views
15

2つの値とファンクタまたはラムダを受け入れるテンプレート関数を記述したいと思います。 関数は、これらの値を持つファンクタを呼び出し、その結果を返します。ファンクタの戻り値の型を推測する方法は?

template <typename T, typename Fn> 
_ReturnTypeOfPred_ Apply(T x, T y, Fn fn) 
    { 
    return fn(x, y); 
    } 

質問:どのように私はFnの戻り値の型に等しくなるようにApplyの戻り値の型を定義することができますか?なお、第1実施例を単純化した

ファンクタ

template <typename T> 
auto Sum(T x, T y) -> decltype(x+y) 
    { 
    return x+y; 
    } 

更新のこの例のように、Tに必ずしも等しくありません。 これは動作しますか?私は戻り値の型のdecltypereturn表現を繰り返した場合

template <typename TContainer, typename Fn> 
auto Apply(const TContainer& x, const TContainer& y, Fn fn) -> decltype(fn(x.front(), y.front())) 
    { 
    return fn(x.front(), y.front()); 
    } 

は、それは常に動作しませんか?よりエレガントな方法がありますか?

+2

実装のために下位の資本名が予約されている。あなた自身のコードでそれらを使用してはいけません。 –

+2

@KerrekSB:これはプレースホルダであり、実際のコードではありません – Andrey

+0

良いファンクタ(STLのものなど)は常に 'return_type'を定義していますので、' Fn :: return_type'を使うことができます。しかし、私は、あまりにも良いものではないファンクタのための答えがほしいと思っています。 – Gorpik

答えて

18

あなたはほぼそこにいます。ただdecltypeを使用します。

template <typename T, typename Fn> 
auto Apply(T x, T y, Fn fn) -> decltype(fn(x, y)) 
{ 
    return fn(x, y); 
} 

あなたはstd::result_ofDifference between std::result_of and decltype)を使用しますが、なぜわざわざだろうか?フォローアップの質問について

template <typename T, typename Fn> 
typename std::result_of<Fn, T, T>::type Apply(T x, T y, Fn fn) 
{ 
    return fn(x, y); 
} 

decltype(<expression>)return-typeを代入する関数の

auto fn(<args>) -> <return-type> { return <expression>; } 

通常動作しますが、エラーが発生しやすくすることができます。たとえば、考えてみます。ここ

auto f(char c) -> decltype(std::string() += c) { return std::string() += c; } 

decltypestd::string &を得られますし、あなたの機能は、ローカルに左辺値参照を返します!例えばあることの理由のために返品しない値を得ることができ、他の場合には

auto f(char c) -> std::remove_reference<decltype(std::string() += c)>::type { 
    return std::string() += c; 
} 

<expression>:これは、に変更されなければなりませんラムダなどを含む、コピー不可能である。

+0

ありがとう、更新された質問をご覧ください。 – Andrey

+0

@Andrey上記を参照してください。 – ecatmur

+0

あなたがリンクした質問は 'std :: result_of'と' decltype'の違いを強調していません。 OPの目的上、 'std :: result_of'は適切ではありません。 –

関連する問題