19

使用带有 CRTP 的模板模板参数时,尝试在派生初始化列表中调用基类构造函数时出现编译错误。

可以使用以下代码片段复制问题:

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

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

令人讨厌的错误消息:

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.

这个问题似乎只发生在 clang (3.4) 上,而不是 g++ (4.8, 4.7, 4.6)。我也在用 -std=c++11 编译。

这是我第一次需要使用带有模板模板参数的 CRTP。我这样做还好吗,这是否是 clang++ 的问题?

我最近比 g++ 更信任 clang++ 错误消息!

4

1 回答 1

17

你的代码是合法的。

来自 C++11 标准,第 14.6.1 节:

像普通(非模板)类一样,类模板有一个注入类名(第 9 条)。注入的类名可以用作模板名或类型名。当它与模板参数列表一起使用时,作为模板模板参数的模板参数,或作为朋友类模板声明的详细类型说明符中的最终标识符,它指的是类模板本身.

看起来您的版本clang仍在执行旧规则。根据您的其他评论,它可能仅在ctor-initializer-list中这样做。


用户David Rodríguez - dribeas为尚未完全实现 C++11 注入类名规则的编译器提供了一种解决方法。使用任何非限定类的名称,例如:

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

一些编译器可能在继承列表中也需要这个:

template <class T>
struct derived : public base< ::derived, T >
//                            ^^
于 2013-07-16T21:45:03.937 回答