プログラミング言語C++において、オーバーロードされた関数群をテンプレートパラメータへ引き渡す方法。
テンプレート引数の関数型を一意に推論できないため、ジェネリックラムダ式でラップする必要がある。テンプレート引数F
はラムダ式に対応する固有のクロージャ型へと推論され、operator()
演算子の呼び出しまでオーバーロード解決が遅延される。
#include <utility> // オーバーロードされた関数f void f(int); void f(int, int); // 1引数バージョンを呼び出す template <class F> void call1(F f) requires requires { f(0); } { f(42); } // 2引数バージョンを呼び出す template <class F> void call2(F f) requires requires { f(0, 0); } { f(1, 2); } int main() { // NG: ill-formed call1(f); call2(f); // GCC: no matching function for call to 'callN(<unresolved overloaded function type>)' // couldn't deduce template parameter 'F' // Clang: no matching function for call to 'call1N' // couldn't infer template argument 'F' // MSVC: no matching overloaded function found // could not deduce template argument for 'F' // OK: ジェネリックラムダ式 auto g = []<class... Ts>(Ts&&... args) { return f(std::forward<Ts>(args)...); }; call1(g); call2(g); }
C++20機能を使えない場合のフォールバック実装:
// C++14/17: SFINAE版 template <class F> auto call1(F f) -> decltype(f(0), void()) { f(42); } template <class F> auto call2(F f) -> decltype(f(0, 0), void()) { f(1, 2); } auto g = [](auto&&... args) { return f(std::forward<decltype(args)>(args)...); };
関連URL
- cpprefjp ジェネリックラムダのテンプレート構文