问题描述
为什么以下代码会编译:
Why does the following code compile:
template<typename T>
void foo(T in) { bar(in); }
struct type{};
void bar(type) {}
int main() { foo(type()); }
以下情况除外:
template<typename T>
void foo(T in) { bar(in); }
void bar(int) {}
int main() { foo(42); }
使用GnuC ++ 7进行编译:
Compiling with GnuC++ 7:
a.cpp: In instantiation of 'void foo(T) [with T = int]':
a.cpp:9:20: required from here
a.cpp:2:21: error: 'bar' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
void foo(T in) { bar(in); }
~~~^~~~
a.cpp:8:6: note: 'void bar(int)' declared here, later in the translation unit void bar(int) {}
我认为MSVC会编译两者(确实如此),但GCC会拒绝两者,因为GCC/Clang具有正确的两阶段名称查找...
I would assume that MSVC would compile both (as it does) but that GCC would reject both since GCC/Clang have proper two phase name lookup...
推荐答案
奇怪的部分不是int
示例无法编译,而是type
示例执行了,因为bar
是在.这是由于[temp.dep.candidate](请参阅第三段).
The strange part is not that the int
example fails to compile, it is that the type
example does since bar
is defined after foo
. This is due to [temp.dep.candidate] (see third paragraph).
当编译器解析并编译模板类或函数时,它将通过两遍查找标识符:
When the compiler parses and compiles a template class or function, it looks up identifiers in two pass:
- 模板参数独立名称查找:可以检查所有不依赖模板参数的内容.在这里,由于
bar()
取决于模板参数,因此什么也没做.查找是在定义时完成的. - 依赖模板参数的名称查找:现在可以通过通行证#1查找所有内容.查找是在实例化时完成的.
- Template argument independent name lookup: everything that does not depend on the template arguments can be checked. Here, since
bar()
depends on a template argument, nothing is done. This lookup is done at the point of definition. - Template argument dependent name lookup: everything that could not be looked up in pass #1 is now possible. This lookup is done at the point of instantiation.
在通行证2中出现错误.
You get an error during pass #2.
查找函数名称时,它是在当前上下文和参数类型的上下文中完成的.例如,尽管在名称空间n
中定义了f
,以下代码仍然有效:
When a function name is looked up, it is done within the current context and those of the parameters type. For instance, the following code is valid though f
is defined in namespace n
:
namespace n { struct type {}; void f(type) {}; }
int main() { n::type t; f(t); } // f is found in ::n because type of t is in ::n
两遍编译,ADL查找和非限定ID查找
在您的情况下,这三种机制相互冲突.参见[临时候选人]:
Two-pass compilation, ADL lookup and unqualified-id lookup
In your case, those three mechanisms collide. See [temp.dep.candidate]:
因此,使用foo(type())
进行非限定ID查找并在在模板定义上下文或模板实例化中"完成查找..
以foo(42)
和42
为基本类型,不考虑ADL,而仅考虑定义上下文" .
So, with foo(type())
unqualified-id lookup kicks in and the lookup is done "in either the template definition context or the template instantiation".
With foo(42)
, 42
being a fundamental type, ADL is not considered and only the "definition context" is considered.
这篇关于无法理解int和用户定义类型之间的名称查找差异-可能与ADL相关的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!