我如何将lambda表达式作为参数传递给c ++模板

时间:2016-04-27 05:09:41

标签: c++ templates lambda

我有一个接受函数作为参数的模板。

当我尝试传递lambda表达式时,它不会编译。

typedef int (*func)(int a);
template <func foo>
int function(int a)
{
    foo(a);
}

int test(int a)
{
    return a;
}

int main()
{
    function<test>(1);   // ---> this is ok

    auto lambda = [](int a) -> int { return a; };
    function<lambda>(1); // ---> this is wrong, why?

    return 0;
}

我缺少什么?

4 个答案:

答案 0 :(得分:11)

lambda不是函数指针! lambda是编译器生成的类的一个实例!

但是,非捕获lambda可以使用它operator+

转换为函数指针

以下是一个例子:

int main() {
    auto lambda = [](int a) { return a; };

    func ptr = +lambda; // this would work

    return 0;
}

可悲的是,operator+在您的情况下甚至不起作用,因为它尚未声明为constexpr,因此您无法在模板参数中使用它。

对你的案例进行修复将使用免费函数......直到N4487不被接受为止,你不能指望将lambda作为模板参数传递。

另一种解决方法是创建自己的仿函数而不是lambda:

struct LambdaType {
    constexpr LambdaType() = default;

    int operator()(int a) {
        return run(a);
    }

    // this is a non-capturing lambda, the operator can be
    // in a static function
    static int run(int a) {
        return a;
    }
};

int main() {
    LambdaType lambda;

    function<&LambdaType::run>(1); // ---> this is working

    return 0;
}

此解决方案不太吸引人,但如果{c}文件中隐藏了LambdaType,则可能会有用。

如果您的目标只是编译器能够内联您的代码,您可以使用模板来传递lambda:

#include <iostream>

template <typename T>
int function(T foo, int a) {
    return foo(a);
}

int main() {
    int a;
    std::cin >> a;

    int b = function([](int a) { return a; }, a);

    return b;
}

由于编译器知道每个instanciation的T类型,一个好的编译器应该能够优化lambda。

使用clang,第三个选项提供以下程序集:

main:                               # @main
    pushq   %rax
    leaq    4(%rsp), %rsi
    movl    std::cin, %edi
    callq   std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
    movl    4(%rsp), %eax    # this is the call to the function
    addq    $8, %rsp
    retq

    pushq   %rax
    movl    std::__ioinit, %edi
    callq   std::ios_base::Init::Init()
    movl    std::ios_base::Init::~Init(), %edi
    movl    std::__ioinit, %esi
    movl    $__dso_handle, %edx
    popq    %rax
    jmp     __cxa_atexit            # TAILCALL

我使用-std=c++14 -Ofast -march=native作为标记。

答案 1 :(得分:6)

这是因为lambda是自己的类型 您已对传递的函数类型进行了function()的模板化。

template<typename F>
int function(F foo, int a) {
    return foo(a);
}

int test(int a) {
    return a;
}

int main()
{
    // function will work out the template types
    // based on the parameters.
    function(test, 1);
    function([](int a) -> int { return a; }, 1);
}

答案 2 :(得分:4)

我不知道标准是否足以说明这是否是我的编译器故障没有正确实现它或者它实际上是标准,但是使用VS2015你不能生成编译时常量lambda表达式。模板只占用编译时常量,所以没有lambdas。

但是,如果要传递lambda,则不需要将其作为模板。没有:

,这完全可能
#include <functional>

int function(std::function<int(int)> const& f, int a)
{
    f(a);
}

int test(int a)
{
    return a;
}

int main()
{
    auto lambda = [](int a) -> int { return a; };

    function(test, 1);
    function(lambda, 1);

    return 0;
}

答案 3 :(得分:1)

这只是因为&#34;您不能使用局部变量的名称或地址作为模板参数。&#34;。 如果要创建全局静态lambda,请参阅 http://jaaslounge.sourceforge.net/ 你可能会找到你想要的东西。