8

次のコード スニペットがあります。これはまったく些細なことですが、より一般的なコードで使用しようとしているパターンを示しています。

template<typename InT, typename ResT>
ResT unary_apply( InT val, std::function<ResT(InT)> fn )
{
    return fn(val);
}

関数ポインター、ファンクター、ラムダなどで unary_apply を呼び出せるようにしたいので、 を使用std::functionしてすべてを抽象化します。

上記を次のように使用しようとすると、C++ (g++ 4.7) は関連する型推論を実行できません。

double blah = unary_apply( 2, []( int v ) { return 3.0 * v; } );

失敗する

src/fun.cpp:147:75: error: no matching function for call to ‘unary_apply(int, test()::<lambda(int)>)’
src/fun.cpp:147:75: note: candidate is:
src/fun.cpp:137:6: note: template<class InT, class ResT> ResT unary_apply(InT, std::function<ResT(InT)>)
src/fun.cpp:137:6: note:   template argument deduction/substitution failed:
src/fun.cpp:147:75: note:   ‘test()::<lambda(int)>’ is not derived from ‘std::function<ResT(double)>’

そして、テンプレート パラメーターを明示的に指定する必要があることがわかりました (実際には、推論できないのは戻り値の型だけだと思います)。

double blah = unary_apply<int, double>( 2, []( int v ) { return 3.0 * v; } );

私は C++11 の型推論規則にはあまり詳しくありませんが、上記の動作は妥当なように思えます ( の内部メカニズムによる推論std::functionは、おそらくかなり大きな課題であることがわかります)。私の質問は: 上記の関数を書き直しunary_applyて同じ柔軟性を維持することは可能ですか (2 番目のパラメーターとして渡すことができる関数/ファンクターなどの型に関して)、型推論への手がかりをさらに与えます。呼び出し時にテンプレート パラメータを明示的に指定する必要はありませんか?

4

1 に答える 1

10

もう少しダックタイプに行くとうまくいくはずです:

template <typename T, typename F>
auto unary_apply(T&& val, F&& func) -> decltype(func(val)) {
    return func(std::forward<T>(val));
}
于 2012-07-05T12:17:55.550 に答える