2016-04-11 11 views
4

以下のファンクタは、ラムダラッパーとして動作するように変更されていますか?キャプチャされた変数でラムダをラップするファンクタを作成するには?

template<typename T> 
class F { 
    T f; 
public: 
    F(T t){ 
     f = t; 
    } 
    T& operator()(){ 
    return f; 
    } 
}; 

int main() 
{ 
    int x = 5; 
    F<int (*)(int, int)> f([x](int a, int b){return a+b;}); 
    return 0; 
} 

コンパイラは、それは彼らが二つの異なるものであるという理由だけで何かをキャプチャする場合

error: no matching function for call to 'F<int (*)(int, int)>::F(main()::<lambda(int, int)>)' 
    F<int (*)(int, int)> f([x](int a, int b){return a+b;}); 
+0

'のstd :: function'、例えば、'のstd ::機能 Fを使用します;そして 'F(int、int b){return a + b;});' –

答えて

1

ラムダが直接自由関数ポインタに変換することはできませんと言います。

キャプチャ値を持つラムダは、その状態をどこかに保存する必要がありますが、関数ポインタは単なるメモリアドレスなので、その機能は提供しません。だからあなたは何かをすることを許可されるでしょう

static_cast<int(*)(int,int)>([](int a, int b) { return a+b; }) 

しかし、あなたはそうではありません。

いくつかの解決策が考えられます。

  • は、ほとんどの意味ラムダ(あなたのケースではない良い解決策を呼び出す無料の機能を提供し、関数ポインタを使用せず、代わりにstd::function<int(int,int>)
  • を使用していませんレガシーコードとinerfaceするために使用され、私は
  • は、それ自体でポインタを機能させるラムダからの折り返しを提供テンプレート関数を使用すると思います。解決策と同様にhere
を提案しました
2

もっと複雑です...変数をキャプチャする内部ラムダ関数はそのような関数ではなく、データ構造です。開発されたソリューションが見つからず、多くのリクエストと質問が解決されていない場合、std :: functionやその他の標準関数や依存関係を使用しないラムダポインタをラップするための最小限のコードを開発しました。 Pure C++ 11。

すべての種類のラムダキャプチャ、参照による参照、戻り値のvoidを受け入れ、トップレベルの関数とメンバメソッドをサポートします。

// Type checkers 
template<typename _Type> 
struct IsVoid 
{ 
    static const bool value = false; 
}; 

template<> 
struct IsVoid<void> 
{ 
    static const bool value = true; 
}; 

// Callable signature interfce 
template<typename _ReturnType, typename..._ArgTypes> 
struct Callable 
{ 
    typedef _ReturnType ReturnType; 
    typedef _ReturnType (*SignatureType)(_ArgTypes...); 

    virtual _ReturnType operator()(_ArgTypes...args) = 0; 
}; 

// Function and lambda closure wrapper 
template<typename _ClosureType, typename _ReturnType, typename..._ArgTypes> 
struct Closure: public Callable<_ReturnType, _ArgTypes...> 
{ 
    typedef _ClosureType ClosureType; 

    const _ClosureType closureHandler; 

    Closure(const _ClosureType& handler) 
     : closureHandler(handler) 
    { 
    } 

    _ReturnType operator()(_ArgTypes...args) override 
    { 
     if(IsVoid<_ReturnType>::value) 
      closureHandler(args...); 
     else 
      return closureHandler(args...); 
    } 
}; 

// Fuction template selector 
template <typename _FunctionType> 
class Function 
    : public Function<decltype(&_FunctionType::operator())> 
{ 
}; 

// Function, lambda, functor... 
template <typename _ReturnType, typename... _ArgTypes> 
class Function<_ReturnType(*)(_ArgTypes...)> 
{ 
public: 
    typedef Function<_ReturnType(*)(_ArgTypes...)> SelfType; 
    typedef _ReturnType(*SignatureType)(_ArgTypes...); 
    Callable<_ReturnType, _ArgTypes...>* callableClosure; 

    Function(_ReturnType(*function)(_ArgTypes...)) 
     : callableClosure(new Closure<SignatureType, _ReturnType, _ArgTypes...>(function)) 
    { 
    } 

    // Captured lambda specialization 
    template<typename _ClosureType> 
    Function(const _ClosureType& function) 
     : callableClosure(new Closure<decltype(function), _ReturnType, _ArgTypes...>(function)) 
    { 
    } 

    _ReturnType operator()(_ArgTypes... args) 
    { 
     if(IsVoid<_ReturnType>::value) 
      (*callableClosure)(args...); 
     else 
      return (*callableClosure)(args...); 
    } 
}; 

// Member method 
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes> 
class Function<_ReturnType(_ClassType::*)(_ArgTypes...)> 
{ 
public: 
    typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...)> SelfType; 
    typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...); 

    SignatureType methodSignature; 

    Function(_ReturnType(_ClassType::*method)(_ArgTypes...)) 
     : methodSignature(method) 
    { 
    } 

    _ReturnType operator()(_ClassType* object, _ArgTypes... args) 
    { 
     if(IsVoid<_ReturnType>::value) 
      (object->*methodSignature)(args...); 
     else 
      return (object->*methodSignature)(args...); 
    } 
}; 

// Const member method 
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes> 
class Function<_ReturnType(_ClassType::*)(_ArgTypes...) const> 
{ 
public: 
    typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...) const> SelfType; 
    typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...) const; 

    SignatureType methodSignature; 

    Function(_ReturnType(_ClassType::*method)(_ArgTypes...) const) 
     : methodSignature(method) 
    { 
    } 

    _ReturnType operator()(_ClassType* object, _ArgTypes... args) 
    { 
     if(IsVoid<_ReturnType>::value) 
      (object->*methodSignature)(args...); 
     else 
      return (object->*methodSignature)(args...); 
    } 
}; 

テスト:

#include <iostream> 

class Foo 
{ 
public: 
    int bar(int a, int b) 
    { 
     return a + b; 
    } 
}; 

int someFunction(int a, int b) 
{ 
    return a + b; 
} 

int main(int argc, char** argv) 
{ 
    int a = 10; 
    int b = 1; 

    // Lambda without capturing 
    Function<int(*)(int)> fn1([] (int b) -> int { 
     return b; 
    }); 

    std::cout << fn1(2) << std::endl; // 2 

    // Lambda capturing variable 
    Function<int(*)(int)> fn2([a] (int c) -> int { 
     return a + c; 
    }); 

    std::cout << fn2(-7) << std::endl; // 3 

    // Lambda capturing scope 
    Function<int(*)(int)> fn3([&] (int c) -> int { 
     return a + c; 
    }); 

    std::cout << fn3(-5) << std::endl; // 5 

    // Arguments by reference 
    Function<void(*)(int&, int)> fn4([] (int& d, int f) { 
     d = d + f; 
    }); 

    fn4(a, -3); // Void call 

    std::cout << a << std::endl; // 7 

    // Top level function reference 
    Function<int(*)(int, int)> fn6(someFunction); 

    std::cout << fn6(a, 4) << std::endl; // 11 

    // Member method 
    Foo* foo = new Foo(); 
    Function<int(Foo::*)(int,int)> fn7(foo->bar); 
    std::cout << fn7(foo, a, 8) << std::endl; // 15 
} 

はGCC 4.9 WIH正しく動作します。

ご質問ありがとうございます。

+1

[私はこのコードに問題があります](http:// ideon.com/j2Qz1K) – mak

+0

Hum ...これはコードの最適化によるものです。 'g ++ -Ox'がなければ(正しく動作する)(http://coliru.stacked-crooked.com/a/ae63c6895124e850)。私はすぐに再検討する – joas

0

decltypeで簡単な回避策を使用してください。

auto lambda = [x](int a, int b){return a+b;}; 
F<decltype(lambda)> f(lambda); // OK 

それは簡潔に見えるように、我々はマクロを使用することができます。

#define DECLARE_F(OBJECT, LAMBDA) \ 
    auto lambda = LAMBDA; \ 
    F<decltype(lambda)> OBJECT(lambda) 

Usage

DECLARE_F(f, [x](int a, int b){return a+b;}); // 1 per line if used ## __LINE__ 
関連する問題