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

Template base constructor call in member initialization list error

本文关键字:函数调用 出错 初始化 列表 成员      更新时间:2023-10-16

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

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中得到以下错误。

错误:类"Foo"没有任何名为"Base"的字段

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

编辑

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

: Base<Foo>(someValue, parent)

编辑

是的,这看起来确实像一个bug。我之前提到的修复了osx下的错误,代码在fedora中可以很好地编译。将去看看os x中是否有对gcc的更新。

第一个:

[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

-结束示例]

对于这里的基,Base应该是一个有效的注入类名(也就是说,你可以用它来代替Base<T>):

[C++11: 14.6.1/1]:与普通(非模板)类一样,类模板有一个注入的类名(第9条)。注入的类名可以用作模板名类型名当它与模板参数列表一起使用时,用作模板模版参数,或用作详细类型说明符中的最终标识符在友元类模板声明中,它引用类模板本身。否则,它等效于<>中包含的类模板的模板名称,后跟的模板参数

[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初始值设定项,所以我认为这是一个编译器错误。

我的精简测试用例在GCC 4.1.2和GCC 4.3.4中失败,但在GCC 4.5.1(C++11模式)中成功。它似乎被GCC错误189解决了;在GCC 4.5发行说明中:

G++现在实现DR 176。以前G++不支持使用模板基类的注入类名作为类型名,以及对名称的查找在中找到了模板的声明封闭范围。现在查找该名称可以找到注入的类名,它既可以用作类型,也可以用作模板,具体取决于无论名称后面是否跟有模板参数列表。作为由于此更改,以前接受的某些代码可能由于

  • 注入的类名不可访问,因为它来自私有基,或者
  • 注入的类名不能用作模板模板参数的参数

在这两种情况下,都可以通过添加嵌套的名称说明符显式命名模板。第一个罐子与-fno访问控制一起工作;第二个只被拒绝与——迂腐。


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

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