n. *_* m. 7 c++ lambda gcc clang argument-dependent-lookup
这个最小的程序
template <typename X>
void foo (X x)
{
bar (x);
}
template <typename X>
void bar (X x)
{
}
int main ()
{
foo ([]{});
}
Run Code Online (Sandbox Code Playgroud)
用gcc编译(4.8.5和5.3)并且无法用clang编译(3.7)
我的分析如下.
bar用于foo和声明之后foo,因此它在foo定义点不可见.bar在foo实例化点可以找到唯一的方法是通过参数依赖查找.
双方的唯一参数foo,并bar在规定的拉姆达main.
显然gcc认为它的类型是在全局命名空间中声明的,而clang则没有.因此,gcc可以bar通过ADL和clang找不到.
当我们使用本地定义的类型时会发生同样的事情main:
int main ()
{
struct K{};
foo (K()); // gcc compiles, clang complains
}
Run Code Online (Sandbox Code Playgroud)
看起来gcc在这里错了.根据标准的lambda类型是未命名的(expr.prim.lambda/3),因此它不应属于任何名称空间.据推测,本地类型也不应该属于全局命名空间.
分析是否正确?这是一个已知的gcc bug吗?
这个问题的灵感来自于这个问题.
根据DR1690/1691的分辨率,GCC是正确的.
闭包类型在包含相应lambda表达式的最小块作用域,类作用域或命名空间作用域中声明.[ 注意:这确定了与闭包类型相关联的名称空间和类的集合([basic.lookup.argdep]).lambda声明符的参数类型不会影响这些关联的命名空间和类.- 结束说明 ]
如果
T是类类型(包括联合),则其关联的类是:类本身; 它所属的成员,如果有的话; 及其直接和间接基类.其关联的命名空间是其关联类的最内部封闭命名空间.
有问题的闭包类型的最内部封闭命名空间是全局命名空间,因此全局命名空间是关联的命名空间.