【问题标题】:Template base constructor call in member initialization list error成员初始化列表错误中的模板基构造函数调用
【发布时间】:2012-02-11 20:35:14
【问题描述】:

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

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”的字段

我应该提到这在我运行 gcc 4.6.2 的 Fedora 机器上编译得很好。在我的 os x Lion 机器上编译时出现此错误。

编辑

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

: Base<Foo>(someValue, parent)

编辑

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

【问题讨论】:

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


【解决方案1】:

第一:

[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 应该是一个有效的 injected-class-name 用于此处的基础(也就是说,您可以使用它来代替 Base&lt;T&gt;):

[C++11: 14.6.1/1]: 与普通(非模板)类一样,类模板有一个injected-class-name(第 9 条)。 injected-class-name 可以用作 template-nametype-name 当它与template-argument-list,作为模板 template-parametertemplate-argument,或作为 中的最终标识符详细类型说明符 在友元类模板声明中,它指的是类模板本身。否则,它相当于 template-name 后跟 &lt;&gt; 中包含的类模板的 template-parameters

[C++11: 14.6.1/3]: 类模板或类模板特化的 injected-class-name 可以用作 template-nametype-名称 无论它在范围内。 [ 例子:

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.4succeeds in GCC 4.5.1 (C++11 mode)。好像被GCC bug 189解决了;在the GCC 4.5 release notes:

G++ 现在实现了DR 176。以前 G++ 不支持使用 模板基类的注入类名称作为类型名称,以及 查找名称在 封闭范围。现在查找名称会找到注入的类名称, 可以用作类型或模板,具体取决于 名称是否后跟模板参数列表。作为一个 由于此更改,以前接受的某些代码可能是 格式不正确,因为

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

在任何一种情况下,都可以通过添加 嵌套名称说明符以显式命名模板。第一个可以 与 -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() {};

【讨论】:

  • 据我了解,他需要在 Foos 的基类初始化中添加一个模板参数,如下所示:Foo::Foo(int someValue, QObject *parent) : Base(someValue, parent) {}
  • @Neox:为什么?为什么base的injected-class-name不够用?
  • 我相信这是一个link to the bug report,已从 gcc 4.5 修复
  • @Jesse:看来你是对的,因为它指的是 DR 176。错误描述似乎与我无关,但我想这是在完全不同的场景中表现出的相同问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-02
相关资源
最近更新 更多