非本地C++11 lambdas是否存在于匿名命名空间中



GCC 4.8的最新版本在头文件中提供了以下代码:

auto L = [](){};
struct S
{
    decltype(L) m;
};

以下警告:

test.hpp:3:8: warning: 'S' has a field 'S::m' whose type uses the anonymous namespace [enabled by default]
 struct S
        ^

为什么编译器会考虑lambda的类型使用匿名命名空间?我使lambda成为全局的,我没有在任何地方使用匿名命名空间。

UPDATE:即使我将lambda放在显式命名空间中,编译也会发出相同的警告,如下所示:

namespace N
{
    auto L = [](){};
}
struct S
{
    decltype(N::L) m;
};

UPDATE 2:事实上,似乎即使是类范围的lambdas也有同样的问题:

class N
{
    static constexpr auto L = [](){};
};
struct S
{
    decltype(N::L) m;
};

§5.1.2/3:

lambda表达式的类型(也是闭包对象的类型)是一个唯一的、未命名的非连接类类型——称为闭包类型——其属性如下所述。此类类型不是聚合(8.5.1)。闭包类型在最小的块作用域、类作用域或命名空间中声明包含相应lambda表达式的作用域。

因此,除非在匿名命名空间内的代码中定义lambda表达式,否则lambda的类型也不应包含在匿名命名空间中。

除非我遗漏了什么,否则这些都不应该在anonyus命名空间中,尽管GCC和MSVC似乎都把它们放在了那里。

§5.1.2 [expr.prim.lambda] p3

[…]闭包类型是在最小的块作用域、类作用域或命名空间中声明的包含相应lambda表达式的作用域。[…]

Atleast Clang似乎做对了,闭包类型位于它应该位于的位置。

(您可以通过简单地将lambda包含在某种产生警告/错误的代码中来测试lambda类型驻留在哪个命名空间中。编译器应该将其类型与警告/错误一起吐出。)

GCC的警告可能有点令人困惑,但其意图肯定是正确的。lambda的类型是未命名的,并且在整个程序中是唯一的。另一方面,如果你的类没有放在一个未命名的命名空间中(根据你的描述,我想不是这样),那么你的类在你包含它的每个翻译单元中都是相同的类型。由于同一个类应该有相同的成员,而不是在不同的翻译单元中有不同的成员,这是一种违规行为(并导致未定义的行为)。

至少同样糟糕的是,L就是extern,因此一旦将标头包含到多个翻译单元中,就会出现"L的多个定义"链接器错误。

在这种情况下,我没有阅读规范,只是想。。。,但是,你能做个测试吗?

您的lambda太琐碎,可能会变成无状态lambda。像您这样的无状态lambda可以通过编译器变成一个简单的C函数。可能有一些规则可以将这些函数放在匿名命名空间中,以便它们只存在于单个编译单元中。

因此,我建议您使它成为非无状态的,就像引用一个变量一样,看看它是否仍然存在于这个匿名命名空间中。

相关内容

  • 没有找到相关文章

最新更新