2

I have the following template class & sample classes :

template<typename A, typename B, typename C = typename A::Nested<B>>
struct X
{
    X()
    {
        std::cout << "A is : " << A::who() << std::endl;
        std::cout << "B is : " << B::who() << std::endl;
        std::cout << "C is : " << C::who() << std::endl;
    }
};

struct Bsample
{
    static const char* who()    { return "Bsample"; }
};

struct Asample
{
    template<typename B>
    struct Nested;
    template<>
    struct Nested<Bsample>
    {
        static const char* who()    { return "Asample::Nested<Bsample>"; }
    };
    static const char* who()    { return "Asample"; }
};

When using vc14, the above code compiles just fine and produces the expected behavior for an instanciation of X<Asample, Bsample> defaulting template parameter C to Asample::Nested<Bsample> .

However, when compiling with GCC 5.1, I get the following error :

prog.cpp:4:65: error: expected '>' before '<' token
 template<typename A, typename B, typename C = typename A::Nested<B>>
                                                                 ^

I tried several combinations to declare the default value for template parameter C, using template, typename, ... but did not succeed in compiling this code with GCC.

How to make this code compliant to C++ standard and compile with GCC ?

Thanks for help

EDIT : Addition to the accepted answer from TartanLlama

In addition to the accepted answer from TartanLlama , I also had to insert a blank (space) between ending template parameters brakets :

template<typename A, typename B, typename C = typename A::Nested<B> >
//                                        blank (space) added here ^

Otherwise, GCC issues the following error (when option -std=c++11 is not specified):

error: spurious '>>', use '>' to terminate a template argument list
 template<typename A, typename B, typename C = typename A::template Nested<B>>
                                                                            ^
shrike
  • 4,449
  • 2
  • 22
  • 38
  • I voted to reopen as this is not just about `template` and `typename`, and it seems like OP is aware of their use, but not sure how to apply it here. – TartanLlama Nov 09 '16 at 09:12
  • @TartanLlama : Sadly, some people close questions faster than light and without even reading them to the end... (I have an idea who did close mine so far.) Thanks for reopening. – shrike Nov 09 '16 at 09:52

2 Answers2

4

You need both typename and template here:

template<typename A, typename B, typename C = typename A::template Nested<B>>

The template says than A::Nested is a template, and the typename says that A::Nested<B> names a type.

You also need to move the specialization of Asample::Nested out of the Asample definition:

struct Asample
{
    template<typename B>
    struct Nested;

    static const char* who()    { return "Asample"; }
};

template<>
struct Asample::Nested<Bsample>
{
    static const char* who()    { return "Asample::Nested<Bsample>"; }
}; 

Live demo

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • I actually tried declaration of the default template parameter as you propose in your answer, but still had a weird error from gcc : `spurious '>>', use '>' to terminate a template argument list`. I just understood that gcc did interpret final `>>` as an extraction operator; inserting a blank between closing brakets fixed the issue. (You may update your answer to mention this if you wish; otherwise I gonna update my question.) Anyway, I will accept your answer as it provides the 2 main fixes to my problem. Thanks. – shrike Nov 09 '16 at 09:42
  • @shrike Yeah, you used to need to have a space between them, but it's fixed in C++11. – TartanLlama Nov 09 '16 at 09:43
1

You need to tell the compiler that Nested is a template:

template<typename A, typename B, typename C = typename A::template Nested<B>>
struct X
{
    // ... 

Regardless, your code will not compile due to a different error:

error: explicit specialization in non-namespace scope 'struct Asample'
     template<>

You need to specialize Nested in namespace scope.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416