3

基本的には、任意のCallable(関数型/ lambda/Functor)を取り、ラムダを返す関数テンプレートを作成します。 -taking-類似引数リストとあなたがgetLambdaFromCallableに変更することができ、元の戻り値の型C++テンプレートのCallableの型(引数リストと戻り値)を推論する方法

#include <iostream> 

int func(int a,float b) { 
    return a+b; 
} 

struct callable { 
    int operator() (int a, float b) { 
     return a+b; 
    } 
}; 

template <typename RV, typename... Args> 
auto getLambdaFromCallable(RV(&func)(Args...)) { 
    auto l = [&](Args... args) -> RV { 
     return func(args...); 
    }; 

    return l; 
} 

int main() { 
    auto f = getLambdaFromCallable(func); 
    std::cout << f(1,2.f); 
    std::cout << " " << typeid(f).name(); 

    auto f2 = getLambdaFromCallable(callable{}); // doesn't work 
    callable{}(1,2); // works 

    auto lambdaTest = [](int a, float b) -> int { 
     return a+b; 
    }; 
    auto f3 = getLambdaFromCallable(lambdaTest); 
} 

答えて

6

の型を返す:

template <typename F> 
auto getLambdaFromFunction(const F& func) { 
    auto l = [&](auto&&... args) 
    -> decltype(func(std::forward<decltype(args)>(args)...)) { 
    return func(std::forward<decltype(args)>(args)...); 
    }; 

    return l; 
} 

この背後にある理由は、以来、あなたが網羅を得ることができないということです関数オブジェクトと呼ぶことができる引数のリスト(multipあなたがすべてを受け入れて呼び出し可能に転送するジェネリックラムダを使用することもできます。


これがどのように機能するかについての詳細を詳しく説明するには、次の

  • auto&&...部分は、ラムダの呼び出し演算子のテンプレート引数リストに変換されます。

  • FgetLambdaFromFunctionと呼ばれています(constはなく、必要に応じて変更することができます)。

  • decltype(args)詳細はstd::forwardを参照して、今度は左辺値と右辺値参照の両方を正しく転送するために存在しているstd::forwardを使用するだけであります。

生成されたラムダオブジェクトは次のようになります。あなたがして、それをコンパイルすることができ

#include <functional> 

template <typename OBJ> 
auto getLambdaFromCallable(OBJ&& obj) 
{ 
    return [&](const auto&... args) { 
       return std::invoke(std::forward<OBJ>(obj), args...); 
     }; 
} 

template <typename F> 
class generatedLambda 
{ 
public: 
    template <typename... Args> 
    auto operator()(Args&&... args) -> decltype(func(std::forward<decltype(args)>(args)...)) 
    { 
    return func(std::forward<decltype(args)>(args)...); 
    } 

private: 
    F  func; 
}; 
+0

' - > decltype(auto)'(参照を扱うための)ラムダの戻り値の型です。 – Jarod42

+0

でも ' - > decltype(func(std :: forward (args)...))'なので、SFINAEフレンドリーです。 – Jarod42

+0

@ Jarod42ありがとうございました。 – Drax

2

あなたがC++ 17を使用することができた場合は、std::invokeは右のツールです。 g++ -std=c++17またはclang++-5.0 -std=c++1zとなり、これはそのまま使用できます。

+0

ありがとう、非常に便利で読みやすいように見える – barney

+1

@barneyありがとう。私は、引数の転送に関することを単純化する入力が変更されていないと仮定しました。ここでは単純なconst refが代わりにあります。私はまた、すべての詳細で説明されているDraxソリューションが好きです。 –

関連する問題