Search code examples
c++templatesgccvisual-c++nested

Nested templated type compiles in VisualStudio but not on GCC


I have the following pattern:

template<class T, int Cap>
struct stack_collection
{

};

template<int Cap>
struct generate_stack_collection
{
    template<class T>
    using type = stack_collection<T, Cap>;
};

template<template<class> class Col>
class collection_user
{

};

int main()
{
    collection_user<typename generate_stack_collection<5>::type> col;
}

This compiles fine on visual studio/MSVC, but not on GCC, see: https://godbolt.org/z/W8hdM87cd

I have a feeling I am missing some "template" and/or "typename" directives, but I cannot seem to get GCC to be happy.

what am I missing for this to compile in GCC?

Here is what gcc says:

<source>: In function 'int main()':
<source>:23:64: error: invalid use of template-name 'generate_stack_collection<5>::type' without an argument list
   23 |         collection_user<typename generate_stack_collection<5>::type> col;
      |                                                                ^~~~
<source>:12:15: note: 'template<class T> using type = stack_collection<T, 5>' declared here
   12 |         using type = stack_collection<T, Cap>;
      |               ^~~~
<source>:23:68: error: template argument 1 is invalid
   23 |         collection_user<typename generate_stack_collection<5>::type> col;
      |                                                                    ^
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:23:64: error: invalid use of template-name 'generate_stack_collection<5>::type' without an argument list
   23 |         collection_user<typename generate_stack_collection<5>::type> col;
      |                                                                ^~~~
<source>:12:15: note: 'template<class T> using type = stack_collection<T, 5>' declared here
   12 |         using type = stack_collection<T, Cap>;
      |               ^~~~
<source>:23:68: error: template argument 1 is invalid
   23 |         collection_user<typename generate_stack_collection<5>::type> col;
      |                                                                    ^
Execution build compiler returned: 1

Solution

  • The typename keyword is wrong here, since the type member is not actually a type, but a template. Therefore just get rid of the typename and it'll work for both compilers (msvc is technically wrong in accepting the typename variant, but eh...):

    collection_user<generate_stack_collection<5>::type> col;
    

    However, in this case you are in the situation where you are explicitly instantiating the generate_stack_collection template you have there; if you want to use a dependent template parameter, you have to use the template keyword - but in contrast to typename you add that after the :::

    template<int X>
    using C = collection_user<generate_stack_collection<X>::template type>;
    
    int main()
    {
        C<5> col;
        return 0;
    }
    

    This code should work in any compliant compiler (and will work in gcc/msvc on godbolt if you try it).