We shall play a game. This is the template game. I write to you a function template, and you tell what it does. Ready? Go!
What does this function does?
template<typename T>
void foo() {
T myT{};
}
Easy! We simply create a variable of type T!
Good! Can you tell me what the following does?
template<typename T>
void foo() {
(void) T::thing();
}
We call a member function of T named thing
?
Yes! Okay, I'll try to call that function with a concrete type:
struct Bar {
using thing = int;
};
foo<Bar>();
Do you notice it? You thought that T::thing()
would call a function, but now it simply creates an int! Take a look at how the instanciated function would look like:
template<>
void foo<Bar>() {
// thing is not a function, but a member type!
(void) Bar::thing();
}
This is bad. Things that look like accessing static variables and calling functions is the same syntax as accessing a member type or creating an instance of the member type!
This could lead to some serious error. We don't want to instantiate a type when we want to call a function, nor We want to call a template function when we just wanted to compare some numbers (yes, that syntax can be ambiguous too!). As such, the compiler will assume that things following ::
are not member types or member template, but rather ordinary members.
If the compiler assumed accessing to a static data members but result accessing to a member type, it will throw a compile time error.
But when you really mean to use a member type, you can tell the compiler not to assume you access a data member, but to assume a type:
template<typename T>
void foo() {
// I really want T::thing to be a type!
(void) typename T::thing();
}
But the compiler only have to deal with these assumptions of syntax when parsing expressions using a dependent name. A dependent babe is simply a name that contains a template parameter.
If you want to know more about where and when to put those desambiguating keywords, read this question: Where and why do I have to put the "template" and "typename" keywords?