2016-04-11 89 views
4

下面的仿函數如何被修改爲lambda包裝?如何創建包含帶捕獲變量的lambda的函子?

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 f([x](int a,int b){return a + b;});' –

回答

1

一個lambda可如果它抓住的東西只是因爲他們是兩個不同的東西不能直接轉換爲自由函數指針。

帶捕獲值的lambda必須在某處保存其狀態,但函數指針只是一個內存地址,因此它不提供該功能。所以你會被允許做點什麼

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

但這不是你的情況。

有些解決方案可能是:

  • 不使用函數指針,但使用std::function<int(int,int>)代替
  • 提供調用拉姆達(不是你的情況很好地解決一個免費的功能,主要是指使用與傳統代碼inerface我說
  • 使用模板函數從拉姆達提供包裝本身的功能指針。該解決方案類似建議here
2

它更復雜...捕獲變量的內部lambda函數不是函數,而是數據結構。我沒有找到任何解決方案的開發和許多請求和問題未解決,然後我開發了這個最小的代碼來包裝lambda指針不使用std :: function或任何其他標準函數或依賴。純C++ 11。

接受各種lambda捕獲,引用參數,返回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。

感謝您的問題。

+1

[我對此代碼有問題](http:// ideone.com/j2Qz1K) – mak

+0

嗯...這是因爲代碼優化。沒有'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__