I'm trying to do something like the following:
template <typename T>
struct A
{
template <typename U>
struct AA
{
};
};
template <typename V, template <typename> class W = A<V>::AA> // Causes C3202
struct B
{
};
But the Visual Studio 2010 compiler spits out:
error C3202: 'AA' : invalid default argument for template parameter '', expected a class template
If I replace B with the following template:
// Replace "T" with "int"
template <typename V, template <typename> class W = A<int>::AA>
struct B
{
};
the code compiles fine, but isn't what I want. If the original isn't legal C++, is there an alternative that provides a similar interface for users of the "B" template?
Your code is not a valid C++ code. See the quotes below.
14.2 Names of template specializations [temp.names]
14.2/4
When the name of a member template specialization appears after
.
or->
in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keywordtemplate
. Otherwise the name is assumed to name a non-template.14.2/5
If a name prefixed by the keyword
template
is not the name of a member template, the program is ill-formed. [Note: the keywordtemplate
may not be applied to non-template members of class templates.] Furthermore, names of member templates shall not be prefixed by the keywordtemplate
if the postfix-expression or qualified-id does not appear in the scope of a template. [Note: just as is the case with thetypename
prefix, thetemplate
prefix is allowed in cases where it is not strictly necessary; i.e., when the expression on the left of the->
or.
, or the nested-name-specifier is not dependent on a template-parameter.]
14.2 Names of template specializations [temp.names]
14.2/4
When the name of a member template specialization appears after
.
or->
in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keywordtemplate
. Otherwise the name is assumed to name a non-template.14.2/5
A name prefixed by the keyword
template
shall be a template-id or the name shall refer to a class template. [ Note: The keywordtemplate
may not be applied to non-template members of class templates. — end note ] [ Note: As is the case with thetypename
prefix, thetemplate
prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the->
or.
is not dependent on a template-parameter, or the use does not appear in the scope of a template. — end note ] [ Example:// ... template <class T> struct B { template <class T2> struct C { }; }; // OK: T::template C names a class template: template <class T, template <class X> class TT = T::template C> struct D { }; D<B<int> > db;
— end example ]
So the correct syntax in this situation is:
template <typename T>
struct A
{
template <typename U>
struct AA
{
};
};
template <typename V, template <typename> class W = A<V>::template AA>
// ^^^^^^^^^^^
struct B
{
};
Unfortunately VC2010 doesn't understand the valid syntax, too.
Depending on your definition of "similar", you could change your B
template definition into
template <typename V, typename W = A<V>>
struct B
{
};
and inside struct B
, you can access the inner template as
W::template AA< some_type >
Your users would, however, need to provide the AA-like template wrapped in a class, just as your struct A
.
You could also lower your requirements on compiler compatibility and require MSVC 2013+.
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