【问题标题】:passing C++11 lambda by templated reference通过模板化引用传递 C++11 lambda
【发布时间】:2023-04-07 21:37:02
【问题描述】:

在 gcc 4.5 中,以下代码编译并按预期使用 -std=c++0x

#include <stdio.h>

template<typename H>
void caller(H h)
{
    h();
}

int main()
{
    auto c = [](){ printf("A\n"); };
    caller(c);
    caller([](){ printf("B\n"); });
    return 0;
}

打印,

A
B

但是,如果 caller 被定义为获取引用,

template<typename H>
void caller(H &h)
{
    h();
}

编译器抱怨,

test.cpp: In function ‘int main()’:
test.cpp:61:34: error: no matching function for call to ‘caller(main()::<lambda()>)’
test.cpp:52:6: note: candidate is: void caller(H&) [with H = main()::<lambda()>]

为什么?

这似乎打破了 lambdas 为函数提供值语义的想法,但这意味着我不能内联编写某些小函数,这有点烦人。

(这在较新版本的 gcc 中是否已修复?我还没有机会测试。)

编辑:我刚刚发现以下实际可行:

template<typename H>
void caller(H *h)
{
    (*h)();
}

int main()
{
    auto c = [](){ printf("A\n"); };
    caller(&c);
    caller(&([](){ printf("B\n"); }));
}

我不认为我能得到这样的临时地址。也许这样可以解决问题,尽管要求函数的用户传入闭包的地址而不是方便的引用很烦人。

【问题讨论】:

  • @Vlad:哦,嘿,那个&amp;&amp; 操作员工作了。在这种情况下这意味着什么?我猜不是“和”。我从没见过&amp;&amp;这样用过。
  • @Steve &amp;&amp; 是一个右值引用。
  • 嗯。学习新事物。谢谢!
  • 您使用指针的第二个示例是一个错误。 GCC 4.7.1 fails 编译它。编辑:VS2010 也允许它,但是如果你将警告调高到 4 级,你会得到:warning C4238: nonstandard extension used : class rvalue used as lvalue
  • 在问题的最后,您说您能够获取临时 lambda 的地址。你能告诉我们更多吗。 g++ 将通过 -f permissive 警告允许这样做 - 这是你做的吗?

标签: c++ lambda c++11


【解决方案1】:

您正试图通过非常量引用传递一个临时值。这不适用于任何类型。

改为通过 const 引用传递 lambda。

【讨论】:

  • 谢谢。默认情况下不是 lambdas const 吗?或者至少是不可变的。
  • @Steve 默认是,但是他们可以是mutable
  • 是的,默认情况下它们是不可变的。但这仍然意味着您必须明确使用const H&amp;。不过,我对指针解决方案很好奇-在这种情况下,H 等于 const TheLambdaType,以便 H* 成为 const TheLambdaType *?
  • @AaronMcDaid 正如 Prætorian 所说,获取临时地址是非法的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多