2016-04-11 24 views
4

Aşağıdaki functor lambda sarıcı olarak çalışmak için nasıl değiştirilecek?Lambda'yı yakalanan değişkenle saran functor nasıl oluşturulur?

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; 
} 

derleyici onlar iki farklı şeydir sırf bir şeyler yakalar eğer

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

Kullanım 'std :: function', mesela, 'std :: fonksiyonunu f

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

o özlü görünmesi için, makro kullanabilirsiniz ; 've sonra da F f ([x] (int a, int b) {return a + b;}); –

cevap

1

Bir lambda doğrudan bir serbest işlev işaretçisi dönüştürülemez söylüyor.

Yakalama değerlerine sahip bir lambda, bir yere durumunu kaydetmelidir, ancak bir işlev işaretçisi yalnızca bir bellek adresidir, bu nedenle bu işlevsellik sağlamaz. Bu nedenle, sizin durumunuz bu değil

.

bazı çözümler olabilir:

  • lambda (değil durumda iyi bir çözüm çağıran bir serbest fonksiyonu sağlamak bir işlev işaretçisi kullanımı ancak std::function<int(int,int>) yerine
  • kullanmayın, çok amaçlı eski kodu ile inerface için kullanılabilir I
  • başına işaretçiyi işlev lambda sargıyı temin eden bir şablon işlevi kullanmak say. çözeltiye benzer here
önerilen
2

Daha karmaşık ... İçinde değişkenleri yakalayan lambda işlevleri, fonksiyonlar gibi değil, veri yapıları. Herhangi bir çözüm geliştiremedim ve pek çok istek ve soru çözülmedi, o zaman bu minimal kodu geliştirdim: lambda işaretçisini std :: function ya da herhangi bir standart fonksiyon ya da bağımlılık kullanmıyordum. Saf C++ 11.

Her türlü lambda yakalamalarını, argümanları referans alarak kabul eder, void döndürür ve üst düzey işlevleri ve üye yöntemlerini destekler.

// 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...); 
    } 
}; 

Testler:

#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 doğru çalışır.

Sorunuz için teşekkürler.

+1

[Bu kodla ilgili sorunlarım var] (http: // ideone.com/j2Qz1K) – mak

+0

Hum ... Kod optimizasyonu nedeniyle. 'G ++ -Ox' olmadan [doğru çalışır] (http://coliru.stacked-crooked.com/a/ae63c6895124e850). Yakında gözden geçireceğim – joas

0

decltype ile basit bir çözüm kullanın.

#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__ 
İlgili konular