19

I'm getting compilation errors when trying to call the base class constructor in derived initialization list when using a template template parameter with CRTP.

Problem can be replicated with this snippet of code:

template <template<class> class Derived, class T>
struct base
{
};

template <class T>
struct derived : public base<derived, T>
{
    derived()
        : base<derived, T>()
    { }
};

The offending error messsage:

bug.cpp:10:16: error: template argument for template template parameter must be a class template or type alias template
        : base<derived, T>()
               ^
bug.cpp:10:11: error: expected class member or base class name
        : base<derived, T>()
          ^
bug.cpp:10:11: error: expected '{' or ','
3 errors generated.

This problem only appears to happen on clang (3.4), not g++ (4.8, 4.7, 4.6). I'm compiling with -std=c++11 also.

This is the first time I've needed to use CRTP with template template parameter. Am I doing this okay and it's a problem with clang++ or not?

I've grown to trust clang++ error messages more than g++ of late!

goji
  • 6,911
  • 3
  • 42
  • 59

1 Answers1

17

Your code is legal.

From the C++11 Standard, section 14.6.1:

Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-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-type- specifier of a friend class template declaration, it refers to the class template itself.

Looks like your version of clang is still implementing the old rule. Based on your additional comments, it might be doing so only in the ctor-initializer-list.


User David Rodríguez - dribeas provided a workaround for compilers that haven't fully implemented the C++11 injected-class-name rule. Use any name of the class that isn't unqualified, for example:

derived()
    : base< ::derived, T >()
//          ^^ qualified with global namespace
{ }

Some compilers may require this in the inheritance list also:

template <class T>
struct derived : public base< ::derived, T >
//                            ^^
Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • +1 Did not know that this had changed in C++11. You might want to provide the workaround I had in the now deleted answer. – David Rodríguez - dribeas Jul 16 '13 at 21:50
  • @DavidRodríguez-dribeas: no worries, the new Standard still surprises me frequently. – Ben Voigt Jul 16 '13 at 21:52
  • 1
    I am not worried, on the contrary I learned something. I'd be worried the day I don't learn anything new :) – David Rodríguez - dribeas Jul 16 '13 at 21:54
  • 3
    Note that you need [whitespace between `<` and `::`](http://coliru.stacked-crooked.com/view?id=bc0dcc3299d98f5d4d5ee6a95933c7ac-0e5891ff8107f561b22ca21b6b60d875) in C++03. – Jesse Good Jul 16 '13 at 21:56
  • @JesseGood: Trigraphs strike again? Oh, actually one of the digraphs (`<:` -> `[`). Anyway, fixed. – Ben Voigt Jul 16 '13 at 21:57
  • 1
    @Jesse: Wow, C++11 made an exception to maximal munch for that exact case: "Otherwise, if the next three characters are `<::` and the subsequent character is neither `:` nor `>`, the `<` is treated as a preprocessor token by itself and not as the first character of the alternative token `<:`" 2.5p3 – Ben Voigt Jul 16 '13 at 22:01
  • @BenVoigt: Thanks for digging up the quote. It seems this rule was made especially for this case. – Jesse Good Jul 16 '13 at 22:05
  • Someone post this bug? – tower120 Jul 15 '14 at 11:30
  • @tower120: It affects an old version of clang. Are you still seeing this with the latest version? – Ben Voigt Jul 15 '14 at 14:10
  • @BenVoigt Coliru sees, so ... Yeah... If 3.4 is new enough... http://coliru.stacked-crooked.com/a/72b49073970a3551 – tower120 Jul 15 '14 at 14:27
  • @tower120: 3.4 is the same version used in the question, one year ago. Try with the latest development version before worrying about a bug report. – Ben Voigt Jul 15 '14 at 20:09