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

时间:2012-01-16 23:40:25

标签: c++ qt inheritance compiler-errors g++

我有一个如下所示的基类。

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

      virtual T someFunc() =0;
};

template<typename T>
Base<T>::Base(int someValue)
{}

然后是以下内容。

#include "base.hpp"

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

      virtual Foo someFunc();
};

Foo::Foo(int someValue)
   : Base(someValue)
{}

我从gcc 4.2.1中收到以下错误。

error: class ‘Foo’ does not have any field named ‘Base’

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

提前感谢您的帮助。

修改

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

: Base<Foo>(someValue, parent)

修改

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

1 个答案:

答案 0 :(得分:9)

首先:

  

[C++11: 12.6.2/3]: mem-initializer-list 可以使用任何表示基类类型的 class-or-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
     

- 示例]

此处Base应为基数的有效注入类名(也就是说,您可以使用它代替Base<T>):

  

[C++11: 14.6.1/1]: 与普通(非模板)类一样,类模板有注入类名(第9条)。 inject-class-name 可以用作模板名称类型名称当它与 template-argument-list ,作为模板 template-parameter template-argument ,或作为中的最终标识符阐述了式说明符   朋友类模板声明,它指的是类模板本身。否则,等同于 template-name ,后跟<>中包含的类模板的 template-parameters < / p>

  

[C++11: 14.6.1/3]:类模板或类模板特化的注入类名可以用作模板名称类型名称在范围内的任何位置。 [示例:

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
     

- 示例]

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

我的精简测试用例fails in GCC 4.1.2GCC 4.3.4但是succeeds in GCC 4.5.1 (C++11 mode)。它似乎由GCC bug 189解决;在the GCC 4.5 release notes中:

  

G ++现在实现了DR 176。以前G ++不支持使用   将模板基类的inject-class-name作为类型名称,以及   查找名称后找到模板的声明   封闭范围。现在查找名称找到inject-class-name,   可以用作类型或模板,具体取决于   该名称后面是否有模板参数列表。作为一个   这个变化的结果,以前接受的一些代码可能是   因为

而形成不良      
      
  • 无法访问inject-class-name,因为它来自私有基础,或
  •   
  • inject-name-name不能用作模板模板参数的参数。
  •   
     

在这两种情况中,可以通过添加a来修复代码   nested-name-specifier用于显式命名模板。第一个可以   与-fno-access-control合作;第二个是被拒绝的   与-pedantic。


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

template <typename T>
struct Base { };

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

Derived::Derived() : Base() {};