When I try to compile this code
// void foobar(int);
template <class T>
struct Foo {
void bar(T t) { foobar(t); };
};
void foobar(int);
template class Foo<int>;
with g++ 4.8.2 I get the following error message
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);
^
(With clang 3.4 it's nearly the same).
First, I think the code is correct and should compile, since foobar is a dependent name in the template declaration and should be looked up only in phase two when the template is instantiated. When this is done in the last line, 'foobar(int)' is already declared. The code compiles, BTW, when I uncomment the topmost line, but both declarations are before the instantiation and so this should not matter.
Second, the error message itself seems contradictory to me. It says "no declarations were found at the point of instatiation" which is foo.cc:10:16, and it says it's declared "later" at foo.cc:8:6. For all that I know about numbers and the English language I would call that "before" not "later".
So, is it a bug in gcc or did I get something wrong? Since this seems to me a common usage pattern I can't quite believe that, however.
BTW: when I try out the second example of "Name Resolution for Dependent Types" at MSDN (http://msdn.microsoft.com/en-us/library/dx2zs2ee.aspx) with g++ the result is different from vc++, which (not generally, but in this specific case) would undermine this being a bug in g++.
tl;dr
Foo<int>
doesn't invoke any ADL, butFoo<X>
would (whereX
is a class type).First of all, in this code
foobar
is a dependent name because of (C++14/N3936)[temp.dep]/1
and
t
is a dependent name because it is part of a declarationT t
whereT
is a template parameter and thus a dependent type.Moving onto dependent name resolution, there is
[temp.dep.res]/1
which introduces the fact that names can be both looked up in the definition context, and the instantiation context, and defines where the instantiation context is. I have omitted that for brevity, but in this exampletemplate class Foo<int>;
is the point of instantiation.The next bit is
[temp.dep.candidate]/1
:Those last two parts are the "two phases" of two-phase lookup. (Note - this section changed in wording from C++11 to C++14, but the effect in the same).
In the first phase, 3.4.1, no names are found for
foobar
.So we move onto the second phase. The actual places that names are looked up as described in 3.4.2. The text is long but the here are two of the relevant rules:
So when you instantiate
Foo<int>
, then the second phase of lookup does not introduce any additional namespaces to search.However, if you change your example to have
struct X {};
and then changeint
toX
everywhere, then the code does compile. This is because of the latter bullet point: ADL for an argument of class type does search the enclosing namespace of that class (which is the global namespace now), however ADL for an argument of built-in type does not search the global namespace.