[英]Two-phase name lookup: PODs vs. custom types
When compiling and running the code 编译和运行代码时
#include <iostream>
struct A { A(int){} };
void foo( int ) { std::cout << "foo(int)" << std::endl; }
template< typename T >
struct S {
void bar() { foo( 5 ); }
void foobar() { T t = 5; foo(t); }
};
inline void foo( A ) { std::cout << "foo(A)" << std::endl; }
inline void foo( double ) { std::cout << "foo(double)" << std::endl; }
int main(int argc, char* argv[])
{
S<double> s0;
s0.bar();
s0.foobar();
std::cout << '\n';
S<A> s1;
s1.bar();
s1.foobar();
}
I get the output (using g++ 4.8, clang++ 3.2 or icpc 13.1) 我得到输出(使用g ++ 4.8,clang ++ 3.2或icpc 13.1)
foo(int)
foo(int)
foo(int)
foo(A)
While the last two lines make perfect sense to me considering the two-phase lookup rules, I would expect foo(int) foo(double)
for the first two lines. 虽然考虑到两阶段查找规则,最后两行对我来说非常有意义,但我希望前两行的
foo(int) foo(double)
。
It seems that in this case for the foobar()
call foo()
gets looked up before instantiation which should not be possible. 似乎在这种情况下,
foobar()
调用foo()
在实例化之前被查找,这是不可能的。 Any hints? 任何提示?
Just define foo(double) before S : 只需在S之前定义foo(double):
#include <iostream>
struct A { A(int){} };
void foo( int ) { std::cout << "foo(int)" << std::endl; }
inline void foo( double ) { std::cout << "foo(double)" << std::endl; } //here
inline void foo( A ) { std::cout << "foo(A)" << std::endl; }
template< typename T >
struct S {
void bar() { foo( 5 ); }
void foobar() { T t = 5; foo(t); }
};
int main(int argc, char* argv[])
{
S<double> s0;
s0.bar();
s0.foobar();
std::cout << '\n';
S<A> s1;
s1.bar();
s1.foobar();
}
output : 输出:
foo(int) foo(double)
foo(int)foo(double)
foo(int) foo(A)
foo(int)foo(A)
EDIT : So S::foo is a non-dependent name and is resolved when the template is defined and S::foobar is a dependant name and is resolved when when the template is instantiated. 编辑:所以S :: foo是一个非依赖名称,在定义模板时解析,S :: foobar是一个依赖名称,并在实例化模板时解析。
This is why s1.foobar
can print A (because foo(A) is defined at this point) 这就是为什么
s1.foobar
可以打印A(因为此时定义了foo(A))
Since T
is a template parameter, the expression t
is type-dependent and hence foo
is a dependent name in the function call foo(t)
. 由于
T
是模板参数,因此表达式t
依赖于类型,因此foo
是函数调用foo(t)
的从属名称。 [temp.dep.candidate] 14.6.4.2/1 says: [temp.dep.candidate] 14.6.4.2/1说:
For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:
对于依赖于模板参数的函数调用,使用通常的查找规则(3.4.1,3.4.2,3.4.3)找到候选函数,除了:
For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
对于使用非限定名称查找(3.4.1)或限定名称查找(3.4.3)的查找部分,仅找到模板定义上下文中的函数声明。
For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.
对于使用关联命名空间(3.4.2)的查找部分,仅找到在模板定义上下文或模板实例化上下文中找到的函数声明。
If the function name is an unqualified-id and the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.
如果函数名称是非限定id并且调用将是格式错误或者找到更好的匹配,则相关命名空间内的查找会考虑所有在所有翻译单元中的那些名称空间中引入外部链接的函数声明,而不仅仅是考虑在模板定义和模板实例化上下文中找到的那些声明,则程序具有未定义的行为。
When instantiating S<double>::foobar
, T
is obviously double
and has no associated namespaces. 在实例化
S<double>::foobar
, T
显然是double
并且没有关联的命名空间。 So the only declarations of foo
that will be found are those from the template definition context ( void foo(int)
) as described in the first bullet. 因此,将要找到的
foo
的唯一声明是来自模板定义上下文( void foo(int)
)的声明,如第一个项目符号中所述。
When instantiating S<A>::foobar
, T
is A
. 当实例化
S<A>::foobar
, T
是A
Declarations of foo
from both the definition context 从定义上下文中声明
foo
void foo(int)
and from A
's associated namespace (the global namespace) are found: 从
A
的关联的命名空间(全局命名空间)中发现:
inline void foo( A ) { std::cout << "foo(A)" << std::endl; }
inline void foo( double ) { std::cout << "foo(double)" << std::endl; }
Clearly void foo(A)
is the best match. 显然
void foo(A)
是最佳匹配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.