在基于范围的循环中使用 lambda 的初始值设定项列表
Using an initializer list of lambdas in a range-based loop
使用 gcc 4.9 -std=c++14,我尝试制作一个 lambda 向量:
vector<function<void ()>> v = {[]{cout << "foo";}, []{cout << "bar";}};
for (auto&& a: v) a();
而且效果很好。然后我尝试将 lambda 的初始值设定项列表直接传递给基于范围的 for:
for (auto&& a: {[]{cout << "foo";}, []{cout << "bar";}}) a();
我得到了:
error: unable to deduce 'std::initializer_list<auto>&&' from '{<lambda closure object>main()::<lambda()>{}, <lambda closure object>main()::<lambda()>{}}'
从错误消息的外观来看,我做了一个疯狂的猜测,这可能是因为"lambda 闭包对象"是内置的语言术语,而不是 std::function 的直接等价物(所以没有真正的类型)。
造成这种情况的更深层次原因是什么?此外,这是否与实现相关,或者这种行为是由规范决定的?
每个 lambda 都有自己独特的类型。因此,您可能不会从不同类型的 lambda 构建 std::initializer_list。
根据C++标准(5.1.2 Lambda 表达式)
3 lambda 表达式的类型(这也是 闭包对象)是一个唯一的、未命名的非联合类类型,称为 闭包类型 — 其属性如下所述。
也
6 非泛型 lambda 表达式的闭包类型,没有 lambda-capture 具有公共非虚拟非显式常量转换 函数到指针到具有C++语言链接的函数 (7.5) 具有 与闭包类型的函数相同的参数和返回类型 呼叫接线员。
每个 lamdba 都有自己的类型,因此编译器无法推断出initializer_list
的类型。
你必须告诉你想要哪种类型:
-
对于每个 lambda:
-
由于您的 lambda 不捕获变量,因此您可以将变量衰减为指针以使用
+
,如下所示:for (auto&& a: {+[]{std::cout << "foo";}, +[]{std::cout << "bar";}}) a();
-
使用
function<void()>
:for (auto&& a: {std::function<void()>([]{std::cout << "foo";}), std::function<void()>([]{std::cout << "bar";})}) a();
-
-
对于initializer_list:
for (auto&& a: std::initializer_list<std::function<void()>>{ []{std::cout << "foo";}, []{std::cout << "bar";}}) a();
我在这里学到的一个技巧是使用回顾性演员表。所以手头有这样一个工具:
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
你可以写这样的东西
vector<function<void()>> v = { FFL([]{cout << "foo"; }), FFL([]{cout << "bar"; }) };
for (auto&& a : v) a();
每个 lambda 都是不相关的类型。 碰巧的是,它们都可以转换为 std::function<void()>
,但那是因为std::function
会声称可以转换任何东西,并且当它们可以通过void()
签名调用并且可复制和可破坏时,它将起作用。
在vector
情况下,有一个从其构造函数列表中考虑的std::initializer_list<std::function<void()>>
构造函数。 这将匹配、尝试和编译。
如果没有该参数(矢量 ctor 的列表参数)匹配,{}
语法将改为在其内容中查找通用类型。 没有通用类型,因此失败。
该语言不会搜索每个类型和模板来查找两个(不相关的)lambda 之间可能的通用类型。 它不会读懂你的心思。
你可以做:
using nullary = std::function<void()>;
template<class T>
using il=std::initializer_list<T>;
for(auto f:il<nullary>{[]{ std::cout<<"hello";},[]{std::cout<<" worldn";}}){
f();
}
- 列表.erase 中的 lambda 表达式
- Simulink "Access Violation"写入 C++ lambda 函数捕获列表中的 PWork 变量
- 将 lambda 函数转换为具有混合 lambda 引入器和参数列表的函子结构
- 没有捕获列表的 lambda 通常作为普通函数实现吗?
- C++参数列表中带有省略号的 lambda
- 将类成员指针传递给 Lambda 捕获列表 c++11
- 在为工作线程访问 lambda 中捕获的向量列表中的元素引用时,是否需要互斥锁?
- 与lambda一起使用虚拟继承在初始化列表中捕获此问题的GCC错误
- 在没有捕获列表的情况下访问 lambda 中的变量
- Do=在lambda的捕获列表中捕获this指针
- 如何使可变 lambda 捕获列表的某些成员变得非常量
- 在类中使用时,lambda 捕获列表中的 [this] 和 [&] 是否等效?
- 为什么 lambda 表达式的捕获列表无法使用结构化绑定分解
- C++ lambda 参数列表
- 构造函数初始化列表中可变参数的Lambda捕获
- C++11 lambda捕获列表[=]使用引用
- 带有变量参数列表的c++11 lambda函数
- 构造函数初始值设定项列表中的 Lambda 可以使用哪些标识符
- 是否可以提取 lambda 的捕获列表
- 您可以在类的初始化列表中使用 lambda 吗?