c++ - 成员初始化列表错误中的模板基构造函数调用

标签 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)

编辑

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

最佳答案

第一:

[C++11: 12.6.2/3]: A mem-initializer-list can initialize a base class using any class-or-decltype that denotes that base class type.

[ Example:

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

—end example ]

还有 Base这里应该是一个有效的 injected-class-name (也就是说,您可以使用它来代替 Base<T> ):

[C++11: 14.6.1/1]: Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.

[C++11: 14.6.1/3]: The injected-class-name of a class template or class template specialization can be used either as a template-name or a type-name wherever it is in scope. [ Example:

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

—end example ]

我没有发现任何表明这不适用于 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++ now implements DR 176. Previously G++ did not support using the injected-class-name of a template base class as a type name, and lookup of the name found the declaration of the template in the enclosing scope. Now lookup of the name finds the injected-class-name, which can be used either as a type or as a template, depending on whether or not the name is followed by a template argument list. As a result of this change, some code that was previously accepted may be ill-formed because

  • The injected-class-name is not accessible because it's from a private base, or
  • The injected-class-name cannot be used as an argument for a template template parameter.

In either of these cases, the code can be fixed by adding a nested-name-specifier to explicitly name the template. The first can be worked around with -fno-access-control; the second is only rejected with -pedantic.


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

template <typename T>
struct Base { };

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

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

关于c++ - 成员初始化列表错误中的模板基构造函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8887864/

相关文章:

c++ - 是否可以在vtable中更改任何func指针?

c++ - QTableView外部拖拽

c++ - Qt 5.1.1 with Visual Studio 2012 - 这些 QT 版本不可访问

Java 8 : Better to extend class of static methods or better to call static methods directly?

c++ - 如何将 ANSI 项目转换为 UNICODE 项目?

c++ - 计算 std::set 中低于给定值的元素

c++ - 通过使用虚拟继承避免内存开销

javascript - 为什么在 Node.js 中使用 util.inherits 和 .call 进行继承

c++ - visual studio调试Qt,缺少msvcp140d_app.dll

c++ - Windows下的HDF5作为动态链接库Qt/C++