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
An unqualified name is simply the class, interface, enum or field without package information.
A function call expression such as func(a,b,c) , in which the function is named without the :: scope operator, is called unqualified. When C++ code refers to a function by an unqualified name, the compiler performs a search for a matching function declaration.
Name lookup is the procedure by which a name, when encountered in a program, is associated with the declaration that introduced it. For example, to compile std::cout << std::endl;, the compiler performs: unqualified name lookup for the name std , which finds the declaration of namespace std in the header <iostream>
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With