How to create a functor that wraps a lambda with a captured variable?

How to change the functor below to work as a lambda wrapper?

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

Compiler says

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;} );
+4
source share
3 answers

This is more complicated ... Internal lambda functions that capture variables are not functions as such, they are data structures. I did not find any solution, and many requests and questions were unresolved, then I developed this minimal code to wrap a lambda pointer without using std :: function or any other standard function or dependency. 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.

.

+2

, - , .

-, - , . -

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

.

:

  • , std::function<int(int,int>)
  • , ( , inerface ,
  • , .
+1

Use a simple workaround with decltype.

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

To make it compressed, we can use a macro:

#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__
0
source

All Articles