質問: [](){ return 2; }; std::cout << func(f, g) << std::endl; return 0; } ``` このときラムダ式はユニークな型であるので関数オブジェクト`f`と`g`は別の型です。 なので`func(f, g)`関数呼び出しは型が一致しないので実体化エラーです。 このときに関数オブジェクトでも関数ポインタでも渡せるようにしたいです。 `func(f, g)`や`func(+f, +g)`の様な方法もあると思いますがもともと、関数オブジェクトをテンプレートで渡すこと自体が推奨されていないことなのでしょうか? `std::function`や関数ポインタを引数に取らせるほうがよほどいい方法でしょうか? 追記:7/22 11:34 極端な例ですが ``` template void f(T a){ if constexpr(std::is_same_v){ std::cout << a << std::endl; }else{ static_assert([](){ return false; }()); } } ``` と ``` void f(int a){...} ``` とどちらがいいのでしょうか。(上記の例は簡単な型なのでテンプレートを使わないほうが良さそうですが...)
回答: > > もともと、関数オブジェクトをテンプレートで渡すこと自体が推奨されていないことなのでしょうか? > > > いいえ。基本的には「関数オブジェクトをテンプレートで渡す」スタイルの方が推奨されます。C++標準ライブラリでもこのスタイルを取っています。 本家SOの std::function vs template 質問と回答もご参考にください。 > > `std::function`や関数ポインタを引数に取らせるほうがよほどいい方法でしょうか? > > > * `std::function`方式は、テンプレート方式に比べると呼出しオーバーヘッドが大きくなりがちです。(賢いコンパイラであれば最適化してくれるかもしれません) * 関数ポインタ方式は、ラムダ式を含む関数オブジェクトが「状態」を持つケースで利用できません。つまりインタフェース設計の選択肢が狭まります。 追記にある例であれば、非テンプレートな通常関数を選ぶべきと思います。(この例示の範囲内に限れば)テンプレートを使う理由がなく、必要のない複雑性を持ち込むだけだからです。 強いて "テンプレート+`std::is_same`" を使う理由付けをするならば、`f('X');`のように暗黙に`int`型へ変換可能な型(`char`)を渡したときの挙動が異なります。このような厳密型一致が本当に必要であれば、テンプレート関数を使う必然性が出てきますね。