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

新手上路,请多包涵

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

当我尝试传递 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;
}

我错过了什么?

原文由 gsf 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 958
2 个回答

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

这个解决方案不是很吸引人,但如果 LambdaType 隐藏在 cpp 文件中,它可能会很有用。

如果您的目标只是能够内联代码的编译器,则可以使用模板来传递 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;
}

由于编译器知道每个实例的 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 作为标志。

原文由 Guillaume Racicot 发布,翻译遵循 CC BY-SA 3.0 许可协议

我对标准的了解不够多,无法说明这是我的编译器错误没有正确实现它还是它实际上是标准,但是使用 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;
}

原文由 nvoigt 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题