I have never gotten a great explanation of how template argument deduction really works, so I'm not sure how to explain behavior I'm seeing in the following:
template<typename T>
struct Base
{
protected:
template<bool aBool = true>
static void Bar(int)
{
}
};
template<typename T>
class Derived : public Base<T>
{
public:
void Foo() { Base<T>::Bar<false>(5); }
};
int main()
{
Derived<int> v;
v.Foo();
return 0;
}
This code won't build, and gives the error:
main.cpp: In instantiation of 'void Derived<T>::Foo() [with T = int]':
main.cpp:25:8: required from here main.cpp:19:15: error: invalid
operands of types '<unresolved overloaded function type>' and 'bool'
to binary 'operator<'
If you change the 2 Base<T>
s in Derived to Base<int>
, it compiles. If you change the call to Bar()
to Base<T>::template Bar<false>(5);
, it also compiles.
The one-liner I saw as an explanation for this is that the compiler doesn't know that Bar is a template, presumably because it doesn't know what Base is until a specialization of Derived is declared. But once the compiler starts generating code for Foo()
, Base<T>
has already been defined, and the type of Bar
can be determined. What is causing the compiler to assume the symbol Bar
is not a template, and attempting to apply operator<()
instead?
I assume it has to do with the rules of when templates are evaluated in the compilation process - I guess what I'm looking for is a good comprehensive explanation of this process, such that the next time I run into code like the below, I can deduce the answer without the help of the good people on stack overflow.
Note I'm compiling with g++ 4.7, with c++x11 support.
In this context
Base<T>
is a dependent name. To access a member template of a dependent name you need to add thetemplate
keyword:Otherwise
Base<T>::Bar
will be parsed as a non-template member and<
as less-than.As of why the
template
is required, the reason is two-phase lookup. The error is triggered during the first pass, before the type is substituted, so the compiler does not know what is the definition ofBase<T>
. Consider for example that you added an specialization ofBar
forint
that had a non-templateBar
member (say for example anint
member). Before substitutingT
intoFoo
, the compiler does not know if there is an specialization for the type.