c++ - 如何创建用捕获的变量包装 lambda 的仿函数?

标签 c++ lambda c++14 functor

如何更改下面的仿函数以用作 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;} );

最佳答案

它更复杂......在内部捕获变量的 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 下可以正常工作。

感谢您的提问。

关于c++ - 如何创建用捕获的变量包装 lambda 的仿函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36538145/

相关文章:

c++ - 什么是 undefined reference /未解析的外部符号错误以及如何修复它?

java - 使用 Java 8 lambda 表达式,按内部列表的属性过滤对象列表

c++ - 根据 bool 标准转换每个参数包的值

c++ - Kd 树 : data stored only in leaves vs stored in leaves and nodes

c++ - 带有 NodeJS 订阅者的 ZMQ 发布者服务器

Java 8 和方法引用 - 特别是 compareToIgnoreCase

Haskell-foldl $ lambda Set.empty

c++ - 将通用 Lambda 与 std::find_if 结合使用

c++ - gsl::array_view<const gsl::cstring_view<>> 来自 std::vector<std::string>

c++ - 使用 libp11 和 pkcs11-engine 读取私钥的区别