lambda 的 C++ 三元赋值
Posted
技术标签:
【中文标题】lambda 的 C++ 三元赋值【英文标题】:C++ ternary assignment of lambda 【发布时间】:2020-03-03 05:47:59 【问题描述】:知道为什么下面的 sn-p 不能编译吗?它抱怨错误“错误:操作数到?:有不同的类型”
auto lambda1 = [&](T& arg)
...
;
auto lambda2 = [&](T& arg)
...
;
auto lambda = condition ? lambda1 : lambda2;
【问题讨论】:
【参考方案1】:奇怪的是,如果 lambda 是无捕获的,则可以使用运算符 +
技巧:
auto lambda1 = [](int arg) ... ;
auto lambda2 = [](int arg) ... ;
auto lambda = condition ? +lambda1 : +lambda2; // This compiles!
lambda(2019);
这是可行的,因为+
会将 lambda 转换为函数指针,并且两个函数指针具有相同的类型(类似于 void (*)(int)
)。
使用 GCC 和 Clang(但不使用 MSVC),+
可以省略,lambdas 仍将转换为函数指针。
【讨论】:
这在 Visual Studio 上不起作用。他们允许 lambda 转换为不同的调用转换的扩展阻止了它。 @GuillaumeRacicot,感谢您的留言。您能否提供一个链接,让我可以阅读更多相关信息? Here you go @GuillaumeRacicot 它似乎可以在最近的 MSVC 版本上编译。 godbolt.org/z/ZQLWxy @Brian 哦!这是个好消息。现在我必须更改一些代码。谢谢!【参考方案2】:编译器将各个 lambda 转换为不同的类。 例如,lambda1 的定义等价于:
class SomeCompilerGeneratedTypeName
public:
SomeCompilerGeneratedTypeName(...) // Capture all the required variables here
void operator()(T& arg) const
// ...
private:
// All the captured variables here ...
;
因此编译器生成了两种不同的类型,导致auto lambda = condition ? lambda1 : lambda2;
的类型不兼容
以下方法可行:
auto lambda = condition ? std::function<void(T&)>(lambda1) : std::function<void(T&)>(lambda2);
为了强调这两个 lambda 确实是不同的类型,我们可以使用标准库中的 <typeinfo>
和 typeid
运算符。 Lambda 不是多态类型,因此标准保证在编译时评估“typeid”运算符。这表明即使 RTTI 被禁用,以下示例仍然有效:
#include <iostream>
#include <typeinfo>
int main()
struct T
;
auto lambda1 = [&](T& arg)
return;
;
auto lambda2 = [&](T& arg)
return;
;
std::cout << typeid(lambda1).name() << "/" << typeid(lambda1).hash_code() << std::endl;
std::cout << typeid(lambda2).name() << "/" << typeid(lambda2).hash_code() << std::endl;
return 0;
程序的输出是(使用 GCC 8.3,see on Gobolt):
Z4mainEUlRZ4mainE1TE_/7654536205164302515
Z4mainEUlRZ4mainE1TE0_/10614161759544824066
【讨论】:
完全错误是“错误:操作数?:具有不同的类型'f(const std::vectorSomeCompilerGeneratedTypeName1
和SomeCompilerGeneratedTypeName2
@cow 我添加了一个突出显示答案开头的示例,您可能会觉得它很有趣【参考方案3】:
编译器无法决定auto
应该是什么类型:
auto lambda = condition ? lambda1 : lambda2;
因为每个 lambda 都有不同且唯一的类型。
一种可行的方法是:
auto lambda = [&](T& arg)
return (condition ? lambda1(arg) : lambda2(arg));
【讨论】:
【参考方案4】:它无法编译,因为每个 lambda 都有唯一的类型,?:
没有通用类型。
您可以将它们包装在 std::function<void(T&)>
中,例如
auto lamba1 = [&](T& arg)
...
;
auto lambda2 = [&](T& arg)
...
;
auto lambda = condition ? std::function(lambda1) : lambda2; // C++17 class template deduction
【讨论】:
【参考方案5】:由于 2 个 lambda(lambda1
和 lambda2
)是 2 种不同的类型,?:
无法从 lambda1
和 lambda2
推断出 lambda
的返回类型。发生这种情况是因为这 2 个不能相互转换。
【讨论】:
以上是关于lambda 的 C++ 三元赋值的主要内容,如果未能解决你的问题,请参考以下文章