lambda的C++三元赋值
C++ ternary assignment of lambda
知道为什么以下代码段无法编译吗?它抱怨错误 "error: operands to ?: have different types"
auto lambda1 = [&](T& arg) {
...
};
auto lambda2 = [&](T& arg) {
...
};
auto lambda = condition ? lambda1 : lambda2;
由于 2 个 lambdas(lambda1
和 lambda2
)是 2 个不同的类型,?:
无法从 lambda1
推导出 lambda
的 return 类型] 和 lambda2
。发生这种情况是因为这 2 个不能相互转换。
它无法编译,因为每个 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
编译器无法决定 auto
应该是什么类型:
auto lambda = condition ? lambda1 : lambda2;
因为每个 lambda 都有不同且唯一的类型。
一种可行的方法是:
auto lambda = [&](T& arg) {
return (condition ? lambda1(arg) : lambda2(arg));
}
编译器将各个 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
奇怪的是,如果 lambda 是无捕获的,则可以使用运算符 +
技巧:
auto lambda1 = [](int arg) { ... };
auto lambda2 = [](int arg) { ... };
auto lambda = condition ? +lambda1 : +lambda2; // This compiles!
lambda(2019);
这是有效的,因为 +
会将 lambda 转换为函数指针,并且两个函数指针具有相同的类型(类似于 void (*)(int)
)。
使用 GCC 和 Clang(但不使用 MSVC),+
可以省略,lambda 仍将转换为函数指针。
知道为什么以下代码段无法编译吗?它抱怨错误 "error: operands to ?: have different types"
auto lambda1 = [&](T& arg) {
...
};
auto lambda2 = [&](T& arg) {
...
};
auto lambda = condition ? lambda1 : lambda2;
由于 2 个 lambdas(lambda1
和 lambda2
)是 2 个不同的类型,?:
无法从 lambda1
推导出 lambda
的 return 类型] 和 lambda2
。发生这种情况是因为这 2 个不能相互转换。
它无法编译,因为每个 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
编译器无法决定 auto
应该是什么类型:
auto lambda = condition ? lambda1 : lambda2;
因为每个 lambda 都有不同且唯一的类型。
一种可行的方法是:
auto lambda = [&](T& arg) {
return (condition ? lambda1(arg) : lambda2(arg));
}
编译器将各个 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
奇怪的是,如果 lambda 是无捕获的,则可以使用运算符 +
技巧:
auto lambda1 = [](int arg) { ... };
auto lambda2 = [](int arg) { ... };
auto lambda = condition ? +lambda1 : +lambda2; // This compiles!
lambda(2019);
这是有效的,因为 +
会将 lambda 转换为函数指针,并且两个函数指针具有相同的类型(类似于 void (*)(int)
)。
使用 GCC 和 Clang(但不使用 MSVC),+
可以省略,lambda 仍将转换为函数指针。