模板基构造函数调用成员初始化列表错误

use*_*084 12 c++ inheritance qt compiler-errors g++

我有一个基类,如下所示.

template<typename T>
class Base
{
   public:
      Base(int someValue);

      virtual T someFunc() =0;
};

template<typename T>
Base<T>::Base(int someValue)
{}
Run Code Online (Sandbox Code Playgroud)

然后是以下内容.

#include "base.hpp"

class Foo
   : public Base<Foo>
{
   public:
      Foo(int someValue);

      virtual Foo someFunc();
};

Foo::Foo(int someValue)
   : Base(someValue)
{}
Run Code Online (Sandbox Code Playgroud)

我从gcc 4.2.1得到以下错误.

error: class ‘Foo’ does not have any field named ‘Base’
Run Code Online (Sandbox Code Playgroud)

我应该提一下,在运行gcc 4.6.2的Fedora盒子上编译好.在我的os x Lion机器上编译时会发生此错误.

在此先感谢您的帮助.

编辑

问题似乎是我在调用构造函数时没有在Foo类中指出模板的类型.以下修复了os x中的错误.

: Base<Foo>(someValue, parent)
Run Code Online (Sandbox Code Playgroud)

编辑

是的,这确实看起来像一个bug.我之前提到的修复了os x下的错误,并且代码在fedora中使用该修复程序编译得很好.将去看看os x中是否有gcc更新.

Lig*_*ica 9

第一:

[C++11: 12.6.2/3]:MEM-初始化列表可以使用任何初始化基类类或-decltype,它表示基础类类型.

[ 例如:

struct A { A(); };
typedef A global_A;
struct B { };
struct C: public A, public B { C(); };
C::C(): global_A() { } // mem-initializer for base A
Run Code Online (Sandbox Code Playgroud)

- 末端的例子 ]

并且Base应该是这里基数的有效注入类名(也就是说,您可以使用它来代替Base<T>):

[C++11: 14.6.1/1]: 与普通(非模板)类一样,类模板具有注入类名(第9节).所述注入的类名可以被用作模板名称类型名称.当它与template-argument-list一起使用时,作为模板模板参数的模板参数,或作为 友元类模板声明的详细类型说明符中的最终标识符,它引用类模板本身.否则,它等同于template-name,后跟括在其中的类模板的template-parameters<>.

[C++11: 14.6.1/3]:类模板或类模板特化的inject-class-name既可以用作模板名,也可以用作范围内的类型名.[ 例如:

template <class T> struct Base {
   Base* p;
};

template <class T> struct Derived: public Base<T> {
   typename Derived::Base* p; // meaning Derived::Base<T>
};

template<class T, template<class> class U = T::template Base> struct Third { };
Third<Base<int> > t; // OK: default argument uses injected-class-name as a template
Run Code Online (Sandbox Code Playgroud)

- 末端的例子 ]

我没有发现任何迹象表明这不适用于ctor-initializer,所以我要说这是一个编译器错误.

我的精简测试用例在GCC 4.1.2GCC 4.3.4中失败,在GCC 4.5.1(C++ 11模式)中成功.它似乎是由GCC bug 189解决的; 在GCC 4.5发行说明中:

G ++现在实现了DR 176.以前,G ++不支持使用模板基类的inject-class-name作为类型名称,并且查找名称会在封闭范围内找到模板的声明.现在查找名称会找到inject-class-name,它可以用作类型或模板,具体取决于名称后面是否有模板参数列表.由于此更改,以前接受的某些代码可能格式不正确,因为

  • 注入类名不可访问,因为它来自私有基础,或
  • inject-class-name不能用作模板模板参数的参数.

在这两种情况中,可以通过添加嵌套名称说明符来明确命名模板来修复代码.第一个可以使用-fno-access-control解决; 第二个只是被拒绝了.


我使用Qt的精简测试用例抽象出来了:

template <typename T>
struct Base { };

struct Derived : Base<Derived> { // I love the smell of CRTP in the morning
   Derived();
};

Derived::Derived() : Base() {};
Run Code Online (Sandbox Code Playgroud)