Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a template template parameter default reference other template type parameters?

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?

like image 805
Aaron Avatar asked Sep 12 '14 14:09

Aaron


2 Answers

Your code is not a valid C++ code. See the quotes below.


C++03

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 keyword template. 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 keyword template may not be applied to non-template members of class templates.] Furthermore, names of member templates shall not be prefixed by the keyword template if the postfix-expression or qualified-id does not appear in the scope of a template. [Note: just as is the case with the typename prefix, the template 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.]


C++11

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 keyword template. 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 keyword template may not be applied to non-template members of class templates. — end note ] [ Note: As is the case with the typename prefix, the template 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 ]


Standard-compliant code

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.

like image 174
Constructor Avatar answered Oct 06 '22 03:10

Constructor


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+.

like image 38
Dalibor Frivaldsky Avatar answered Oct 06 '22 03:10

Dalibor Frivaldsky