成员初始化列表错误中的模板基构造函数调用 [英] Template base constructor call in member initialization list error

查看:26
本文介绍了成员初始化列表错误中的模板基构造函数调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a base class that looks like the following:

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

I get the following error from gcc 4.2.1.

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

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

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

I should mention this compiles fine on my Fedora box which is running gcc 4.6.2. This error occurs when compiling on my os x Lion machine.

编辑

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

Problem seems to be that I am not indicating type of template in the Foo class when calling the constructor. The following fixes the error in os x.

: Base<Foo>(someValue, parent)

编辑

是的,这确实看起来像一个错误.我之前提到的修复了 os x 下的错误,并且代码在 Fedora 中通过该修复可以正常编译.去看看os x中gcc有没有更新.

Yes this does look like a bug. What I mentioned before fixes the error under os x and code compiles fine in fedora with that fix. Will go and see if there is an update to gcc in os x.

推荐答案

第一:

[C++11: 12.6.2/3]: mem-initializer-list 可以使用任何 class-or- 初始化基类decltype 表示该基类类型.

[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.

[ 示例:

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;):

And Base should be a valid injected-class-name for the base here (that is, you can use it in place of Base<T>):

[C++11: 14.6.1/1]: 像普通(非模板)类一样,类模板有一个注入类名(第 9 条).injected-class-name 可以用作 template-nametype-name. 当它与模板参数列表,作为模板模板参数模板参数,或者作为中的最终标识符详细类型说明符在友元类模板声明中,它指的是类模板本身.否则,它等价于 template-name 后跟 template-parameters 包含在 <> 中的类模板的template-parameters.

[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]: 类模板或类模板特化的 injected-class-name 可以用作template-nametype-name 范围内的任何位置.[ 示例:

[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

——结束示例 ]

我没有发现任何内容表明这不适用于 ctor-initializer,所以我认为这是一个编译器错误.

I haven't found anything to indicate that this doesn't apply in the ctor-initializer, so I'd say that this is a compiler bug.

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

My stripped-down testcase fails in GCC 4.1.2 and GCC 4.3.4 but succeeds in GCC 4.5.1 (C++11 mode). It seems to be resolved by GCC bug 189; in the GCC 4.5 release notes:

G++ 现在实施 DR 176.以前 G++ 不支持使用模板基类的注入类名称作为类型名称,以及名称的查找发现模板的声明在封闭范围.现在查找名称找到注入的类名称,它可以用作类型或模板,具体取决于名称后面是否跟有模板参数列表.作为一个此更改的结果,以前接受的某些代码可能是格式错误,因为

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

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

在这两种情况中的任何一种情况下,都可以通过添加嵌套名称说明符显式命名模板.第一个可以使用 -fno-access-control 解决;第二个只被拒绝与-迂腐.

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 抽象出来的精简测试用例:


My stripped-down testcase with Qt abstracted out:

template <typename T>
struct Base { };

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

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

这篇关于成员初始化列表错误中的模板基构造函数调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆