我如何将Lambda表达式传递给C ++模板作为参数 [英] How I can pass lambda expression to c++ template as parameter

查看:152
本文介绍了我如何将Lambda表达式传递给C ++模板作为参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a template that accepts a function as an argument.

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

When I try to pass a lambda expression it does not compile.

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

我丢失了什么?

推荐答案

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

A lambda is not a function pointer! A lambda is an instance of compiler generated class!

但是,未捕获的Lambda可以使用其 operator +

However, a non capturing lambda may be converted to a function pointer using it's operator+

下面是一个示例:

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

    func ptr = +lambda; // this would work

    return 0;
}

不幸的是, operator + 甚至在您的情况下都不起作用,因为它没有被声明为constexpr,因此您不能在模板参数中使用它。

Sadly, the operator+ won't even work in your case because it has not been declared as constexpr, so you can't use it in a template parameter.

对案例的修复将使用免费功能...直到不接受 N4487 ,您可以

A fix to your case would be to use a free function... until N4487 is not accepted, you can't expect to pass lambda as template parameter.

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

Another fix would be to create your own functor instead of a 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;
}

此解决方案不太吸引人,但是如果 LambdaType 隐藏在cpp文件中。

This solution is not quite appealing, but it might be useful if LambdaType is hidden in a cpp file.

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

If your goal is only the compiler to be able to inline your code, you can use templates to pass the lambda around:

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

因为编译器知道 T的类型的每个实例,一个好的编译器应该能够优化lambda。

Since the compiler knows the type of T for each instanciation, a good compiler should be able to optimize out the lambda.

使用clang,第三个选项给出了以下汇编:

With clang, the third option gives the following assembly:

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 作为标志。

这篇关于我如何将Lambda表达式传递给C ++模板作为参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆