当我尝试编译这段代码时
// void foobar(int);
template <class T>
struct Foo {
void bar(T t) { foobar(t); };
};
void foobar(int);
template class Foo<int>;
与g ++ 4.8.2我收到以下错误消息
foo.cc: In instantiation of ‘void Foo<T>::bar(T) [with T = int]’:
foo.cc:10:16: required from here
foo.cc:5:27: error: ‘foobar’ was not declared in this scope, and no
declarations were found by argument-dependent lookup at
the point of instantiation [-fpermissive]
void bar(T t) { foobar(t); };
^
foo.cc:8:6: note: ‘void foobar(int)’ declared here, later in the translation unit
void foobar(int);
^
(使用clang 3.4几乎相同)。
首先,我认为代码是正确的并且应该编译,因为foobar是模板声明中的从属名称,并且仅在实例化模板的第二阶段才应进行查找。在最后一行完成此操作时,已经声明了“ foobar(int)”。当我取消注释最顶行时,代码会编译,顺便说一句,但是两个声明都在实例化之前,因此这无关紧要。
其次,错误消息本身似乎与我矛盾。它说“在声明点找不到声明”,即foo.cc:10:16,并说它在foo.cc:8:6声明为“以后”。就我所知道的有关数字和英语的所有知识而言,我会称其为“之前”而不是“以后”。
那么,这是gcc中的错误还是我做错了?但是,由于在我看来这是一种常见的使用模式,因此我无法相信。
顺便说一句:当我尝试使用g ++在MSDN(http://msdn.microsoft.com/en-us/library/dx2zs2ee.aspx)上使用M ++的第二个示例“依赖类型的名称解析”时,结果与vc ++有所不同(不是一般情况,但在这种情况下)会破坏这是g ++中的错误。
tl; dr Foo<int>
不会调用任何ADL,但Foo<X>
会调用(其中X
是类类型)。
首先,foobar
由于(C ++ 14 / N3936),此代码中的从属名称[temp.dep]/1
在以下形式的表达式中:
postfix-expression ( expression-list opt )
如果[...]后缀表达式是一个不合格ID,则不合格ID表示从属名称。
- expression-list中的任何表达式都是类型相关的表达式(14.6.2.2),或者
并且t
是从属名称,因为它是声明的一部分,T t
其中T
是模板参数,因此是从属类型。
转向依赖名称解析,[temp.dep.res]/1
这引入了一个事实,即可以在定义上下文和实例化上下文中查找名称,并定义实例化上下文的位置。为了简洁起见,我省略了它,但是在此示例中template class Foo<int>;
是实例化的要点。
下一位是[temp.dep.candidate]/1
:
对于后缀表达式为从属名称的函数调用,将使用常规查找规则(3.4.1、3.4.2)查找候选函数,但以下情况除外:
- 对于使用非限定名称查找(3.4.1)的查找部分,仅从模板定义上下文中找到函数声明。
- 对于使用关联的名称空间(3.4.2)进行的查找,仅会找到在模板定义上下文或模板实例化上下文中找到的函数声明。
最后两个部分是两阶段查找的“两个阶段”。(注意-本节的措词从C ++ 11更改为C ++ 14,但效果相同)。
在第一个阶段3.4.1中,找不到的名称foobar
。
因此,我们进入第二阶段。按照3.4.2中的描述查找名称的实际位置。文本很长,但是这里有两个相关规则:
如果T是基本类型,则其关联的名称空间和类的集合均为空。
如果T是一个类类型(包括并集),则其关联的类为:类本身;它所属的类(如果有);及其直接和间接基类。其关联的名称空间是其关联类的最内层封闭的名称空间。[...]
因此,当实例化时Foo<int>
,查找的第二阶段不会引入任何其他要搜索的名称空间。
但是,如果将示例更改为拥有struct X {};
,然后更改int
为X
无处不在,则代码会编译。这是因为后一个要点:类类型的参数的ADL会搜索该类的封闭名称空间(现在是全局名称空间),而内置类型的参数的ADL不会搜索全局名称空间。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句