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.
bar
right after foo
and before a specialization of foo<int>
so that this latter can see bar(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:
template <int> // not a specialization, just a different
void foo(int i) // template with a non-type template parameter
{
bar(i);
}
does not actually define a specialization of the foo
primary template. So when you make this call:
Foo<int>(4);
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
for int
like this:
template <> // specialization of primary
void foo<int>(int i) // template foo with int
{
bar(i);
}
then the call foo<int>(4);
is fine, because it calls the specialization, and lookup for bar
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 with print
and do_it
, and this is formally known as ill-formed, no diagnostic required.