I have the following code:
template <typename TC>
class C
{
struct S
{
template <typename TS>
void fun() const
{}
};
void f(const S& s)
{
s.fun<int>();
}
};
// Dummy main function
int main()
{
return 0;
}
When building this with both gcc 9.2 and clang (9.0), I'm getting a compilation error due to the template
keyword being required for invoking fun
. Clang shows:
error: use 'template' keyword to treat 'fun' as a dependent template name
s.fun<int>();
^
template
I don't understand why the compiler thinks fun
is a dependent name in the context of f
, since f
is not a template itself. If I change C
to be a regular class instead of a template, the error goes away; however, I don't see why there should be an error in the first place since neither S
nor f
depend on TC
.
Oddly enough, MSVC 19.22 compiles this just fine.
Before voting to close as dupe of Where and why do I have to put the "template" and "typename" keywords? please consider this is a special case where even if S
is indeed a dependent name, in the context of f
it would not be dependent if not for the fact that they are members of the current instantiation.
Using the TEMPLATE keyword makes it clear to other programmers that the field or data structure is not intended to be used as a program variable. Even when you add a suffix such as _t to the name, the keyword makes it crystal-clear to other programmers.
Templates are an important part of C++, as already mentioned, they allow you to develop functions or Classes that are type generic. You specify the type when you use them. You really should learn templates if, for no other reason, to understand boost and the standard template libraries.
Templates increase flexibility: Templates actually increase flexibility, they're easy to update, and they provide consistency across the project. They can be improved regularly to meet technological and instructional requirements as well as the client's needs. These are easily tracked and updated.
The keywords typename and template are now not required anymore if the qualifier is a member of the current instantiation.
Consider:
template<typename T>
struct C
{
struct S
{
int a = 99;
};
void f(S s, int i)
{
s.a<0>(i);
}
};
template<>
struct C<long>::S
{
template<int>
void a(int)
{}
};
int main()
{
C<int>{}.f({}, 0); // #1
C<long>{}.f({}, 0); // #2
}
s.a<0>(i)
is parsed as an expression containing of two comparison operations <
and >
, and this is fine for #1 but fails for #2.
If this is changed to s.template a<0>(i)
then #2 is OK and #1 fails. Thus the template
keyword is never redundant here.
MSVC is capable of interpreting the expression s.a<0>(i)
both ways within the same program. But this is not correct according to the Standard; each expression should have only one parse for the compiler to deal with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With