9

My problem can be resumed by the following piece of code:

template <typename T> struct C2;

template <typename T> 
struct C1
{
  template <typename Type,
        template <typename Ti> class Container = C2>
  void m() {}
};


template <typename T> 
struct C2
{
  template <typename Type = int,
        template <typename Ti> class Container = C2> // <-- Here is the problem!
  void m() {}

};

The gnu compiler, version 4.8.1 fails with the following message:

test-temp.C:16:47: error: invalid use of type ‘C2<T>’ as a default value for a template template-parameter
      template <typename Ti> class Container = C2> 

It refers to default template parameter C2 for the the method C2::m.

Apparently (it is my opinion), the compiler is seeing C2<T> as default parameter instead of C2 (without <T>). So, when it finds the instruction it fails because type C2<T> does not match with Container.

However, clang++, just for exactly the same code, compiles fine!

My questions:

  1. Which compiler has the truth?
  2. Is there some alternative for expressing the same sense with the current version of gnu compiler?

Thanks in advance

Leandro

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
lrleon
  • 2,610
  • 3
  • 25
  • 38

2 Answers2

9

I think Clang is correct, and g++ is in error, quote from the draft Standard (bold emphasis is mine)

14.6.1 Locally declared names [temp.local]

1 Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injectedclass-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-typespecifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.

You can use the :: scope resolution operator to beat g++ into submission

template <typename T> 
struct C2
{
  template <typename Type = int,
        template <typename Ti> class Container = ::C2> 
                                              // ^^ <-- here is the solution!
  void m() {}

};

Live Example.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • @Irleon glad to have been of help. And welcome to Stackoverflow! – TemplateRex Sep 25 '13 at 20:00
  • 1
    @TemplateRex I hope either Irleon or you checked that GCC has a bug report for this or created one? SO is nice but it doesn't get stuff fixed. I usually link to bugzilla to let people know so the can later check for which version the problem is fixed. (also: +1) – Daniel Frey Sep 25 '13 at 21:52
  • @DanielFrey I'm a bit pressed for time, also the issues has a fairly simple work-around so it won't get high priority probably. Maybe the OP can submit one? BTW, I answered [another likely-bug today](http://stackoverflow.com/q/18994041/819272), be nice to know I got that one right, too. – TemplateRex Sep 25 '13 at 21:57
  • 1
    @TemplateRex I went ahead and reported it as [bugzilla #58538](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58538), let's see how the GCC folks react to it. In my experience the will usually look at it, think about it and if the solution is a small, localized fix somewhere in their codebase, the are incredibly fast. I do wonder if it is important that `C2` is used **as a default** - sometimes the rules for default template (template) parameters are different. Hm... – Daniel Frey Sep 25 '13 at 22:25
  • @DanielFrey tnx for the bug report. For what it's worth: replacing `void f();` with `class Inner;` in your bug report, yields the same error message, so this is not related to the per C++11 lifted restriction on default template arguments for *function* templates. – TemplateRex Sep 26 '13 at 07:27
0

So does the 14.6.1 reference in TemplateRex's answer mean that G++ is correct (and Clang and VC++ are wrong) to accept this, since it uses X as the template argument to a template template parameter?

template< template< typename > class T >
class factory { };

template< typename T >
class X
{
      friend class factory< X >;  // ***
};

int main()
{
}

In this example G++ treats X as the name of the class template, whereas Clang and VC++ treat it as the injected class name.

Edit: Clang 5.0.0 now accepts the code, the same as G++ and EDG.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521