问题
How should this code behave? It calls generic function ignoring my overload if I use qualified name in call_read()
function; and it calls overload first and then generic version if I use unqualified name. What's the difference? Is it a bug in GCC?
#include <iostream>
struct info1 {};
struct info2 {};
template<class T> void read(T& x)
{
std::cout << "generic" << std::endl;
}
template<class T> void call_read(T& x)
{
::read(x); // if I replace ::read(x) with read(x) the overload is called
}
void read(info1& x)
{
std::cout << "overload" << std::endl;
}
int main()
{
info1 x;
info2 y;
call_read(x);
call_read(y);
}
I also noticed that it works different for fundamental types. See the code bellow
#include <iostream>
typedef struct info1 {};
typedef struct info2 {};
typedef int info3;
typedef double info4;
template<class T> void read(T x)
{
std::cout << "generic" << std::endl;
}
template<class T> void call_read(T x)
{
read(x);
}
void read(info1 x)
{
std::cout << "overload" << std::endl;
}
void read(info3 x)
{
std::cout << "overload" << std::endl;
}
int main()
{
call_read(info1());
call_read(info2());
call_read(info3());
call_read(info4());
}
It is supposed to call overloaded function twice, but it's not. See the result here http://codepad.org/iFOOFD52
回答1:
What you're observing is a superposition of two-phase name lookup and argument dependent lookup.
Let's see what the standard says (C++03). [temp.dep]:
[...] In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an identifier, the identifier denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2).
That means that in both read
and ::read
, read
is a dependent name because x
is type-dependent. That means that it's resolved at the point of instantiation. Let's see what are the rules for this [temp.dep.candidate]:
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:
— For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
Therefore for the ::read
case only functions declared before the template definition are considered. But:
— For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.
for the unqualified read
both functions are considered, those visible at template definition and template instantiation.
回答2:
Yes, this is the expected behaviour. In the first case (::read) you effectivly disable ADL (argument dependent lookup) which restricts name lookup to things that have been declared in the global scope before your use of read. If you remove :: ADL will kick which may resolve to functions you declared after your function template.
Edit: And since for fundamental types like int
and double
there is no ADL, this explains your 2nd observation.
回答3:
The compiler will always call the method which match the most your call. Here you call :
read(T& x) [with T = info1]
Thus the compiler will prefer the overload as it precisely match the call. It in the logic of template specializations, which permits to say that if an overloaded function exists which better match your call, then this one will be used.
For the second part of the question, concerning the difference when using fully-qualified and unqualified names, it comes from the fact that fully-qualified name is not dependent to anything else, and is thus resolved to the first match (here your template declaration).
来源:https://stackoverflow.com/questions/8501294/different-behavior-for-qualified-and-unqualified-name-lookup-for-template