我试图使用C ++ 14的通用lambda,但是在使用std :: function时遇到了麻烦。
#include <iostream>
#include <functional>
int main()
{
const int a = 2;
std::function<void(int)> f = [&](auto b) { std::cout << a << ", " << b << std::endl; };
f(3);
}
无法编译,并显示错误消息error: ‘a’ was not declared in this scope
。
如果我将其更改为(int b)
,则无效。
这是一个错误吗?或者我错过了什么?
我使用的GCC版本是4.9.2。
答案 0 :(得分:23)
除非我执行以下任何操作,否则我可以重现此内容:
const
a
a
std::function<void(int)>
更改为auto
auto b
更改为int b
我认为这是一个与优化相关的编译器错误,并且无法在通用lambda中检测 odr-use (尽管设置-O0
没有意义,这很有意思影响)。它可能与bug 61814有关,但我认为它相当同样的事情,因此:
我已将其提升为GCC bug 64791。
当然,我无法在C ++ 14中找到任何明显不应该禁用你的代码的内容,尽管很少有明显的&#34;一般来说在新的C ++ 14中的措辞。 :(
[C++14: 5.1.2/6]:
[..] 对于没有lambda-capture的通用lambda,闭包类型有一个公共的非虚拟非显式const转换函数模板来指向函数。转换函数模板具有相同的发明 template-parameter-list ,并且指向函数的指针具有与函数调用操作符模板相同的参数类型。 [..],则为
[C++14: 5.1.2/12]:
lambda-expression ,其关联的 capture-default 未明确捕获此变量或具有自动存储持续时间的变量(这不包括任何<已发现引用 init-capture 的相关非静态数据成员的em> id-expression 被称为隐式捕获实体(即,如果复合语句:this
或变量
- odr-uses(3.2)实体,或
- 在潜在评估表达式(3.2)中命名实体,其中封闭的full-expression依赖于在 lambda-expression 的到达范围内声明的泛型lambda参数。
[例如:
void f(int, const int (&)[2] = {}) { } // #1 void f(const int&, const int (&)[1]) { } // #2 void test() { const int x = 17; auto g = [](auto a) { f(x); // OK: calls #1, does not capture x }; auto g2 = [=](auto a) { int selector[sizeof(a) == 1 ? 1 : 2]{}; f(x, selector); // OK: is a dependent expression, so captures x }; }
-end example] 所有这些隐式捕获的实体都应在lambda表达式的到达范围内声明。 [注意:嵌套的lambda表达式对实体的隐式捕获可能导致其通过包含的lambda表达式进行隐式捕获(见下文)。隐式 odr-uses 会导致隐式捕获。 -end note]
[C++14: 5.1.2/13]:
如果明确或隐式捕获实体,则捕获该实体。由 lambda-expression 捕获的实体在包含 lambda-expression 的范围内使用odr(3.2)。 [..]
答案 1 :(得分:3)
int main() {
const int a = 2;
auto f = [&](auto b) { std::cout << a << ", " << b << std::endl; };
f(3);
}
不知道它是否适用于std::function
,但这肯定有用。
进一步调查:
我创建了一个类来尽可能地模仿lambda:
class Functor {
private:
int const x;
public:
Functor() : x{24} {}
auto operator()(int b) const -> void { cout << x << " " << b << endl; }
};
std::function<auto(int)->void> f2 = Functor{};
f2(3); // <- this works
这表明你的例子应该有效。所有lambda与行为相同,其中operator()
重载的对象和捕获变量的字段。
如果我们更改课程以转到auto
部分:
这不起作用:
class Functor {
private:
int const x;
public:
Functor() : x{24} {}
auto operator()(auto b) const -> void { cout << x << " " << b << endl; }
};
std::function<auto(int)->void> f2 = Functor{}; // <-- doesn't work
然而这有效:
class Functor {
private:
int const x;
public:
Functor() : x{24} {}
template <class T>
auto operator()(T b) const -> void { cout << x << " " << b << endl; }
};
std::function<auto(int)->void> f2 = Functor{}; // <-- this works
所以很可能它与使用auto
作为lambda / functions的参数有关,这是C ++ 14的新功能,所以很可能没有成熟的实现。