I have written this code to understand template
name lookup:
//void bar(int);
template <typename T>
void foo(T x)
{
bar(x);
}
void bar(int x)
{
std::cout << "bar(int)\n";
}
template <int>
void foo(int i)
{
bar(i);
}
int main()
{
foo<int>(4);
std::cout << "\ndone!\n";
}
I've commented out the declaration of function bar(int)
intentionally. This function bar(int)
is used as a dependent name
in the template function foo
. So it is bound upon instantiation.
- I've defined
bar
right afterfoo
and before a specialization offoo<int>
so that this latter can seebar(int)
.
But when I compile the code I get this error:
‘bar’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]|
. And if I un-comment the declaration of bar(int)
it works fine?!
If I must declare a name before using it in a template as a dependent-name then why C++ allows that if not instantiated. (the code works if I don't "use" templated function
foo
)?template <typename U> void do_it(U u) { print(u); // not bound until instantiation }
So what is the idea behind allowing calling print(u)
in do_it
which was not already declared and will fail upon instantiation?
In your program, this definition:
does not actually define a specialization of the
foo
primary template. So when you make this call:you end up calling the primary template. Lookup for the name
bar
doesn't find that name, and you get an error.If instead, you actually write a specialization of
foo
forint
like this:then the call
foo<int>(4);
is fine, because it calls the specialization, and lookup forbar
at that point does find that name.Now going back to your program (without the specialization), what happens if
foo
is never instantiated, because there's no call, for example? Well, the program is still wrong, but the compiler may not tell you about it. This is the behavior that you are describing withprint
anddo_it
, and this is formally known as ill-formed, no diagnostic required.