模板基础构造函数调用成员初始化列表错误 [英] Template base constructor call in member initialization list error
问题描述
我有一个基类,如下所示。
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.
error: class ‘Foo’ does not have any field named ‘Base’
我应该提到这个编译在我的Fedora框正在运行gcc 4.6.2。在我的os x Lion机器上编译时出现此错误。
I should mention this compiles fine on my Fedora box wich is running gcc 4.6.2. This error occurs when compiling on my os x Lion machine.
感谢您提供帮助。
问题似乎在调用构造函数时,我没有在Foo类中指示模板类型。以下修复了os x中的错误。
Problem seems 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)
EDIT
是的,这看起来像一个错误。我之前提到的修复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]:
A 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
-end example ]
和基本
应该是这里的基础的有效的 inject-class-name (也就是说,您可以使用它代替 Base< T>
):
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]:
与普通(非模板)类类似,类模板具有 inject-class-name (第9条)。 inject-class-name 可用作模板名称或类型名称。 模板参数列表作为模板的模板参数,或作为详细说明了一个朋友类模板声明的
,它引用了类模板本身。否则,它等同于<>
中包含的类模板的 template-name ,后跟 template-parameters / code> 。
[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-name 或 type-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-
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错误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 ++不支持将模板基类的
inject-class-name用作类型名称,而
查找名称在
封闭范围中找到模板的声明。现在查找名称找到inject-class-name,
,它可以用作类型或模板,取决于
,无论名称是否后跟模板参数列表。作为此更改的
结果,以前接受的一些代码可能是
错误,因为
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
- inject-class-name不可访问,因为它来自私有基础,或
- inject-class-name不能用作模板模板参数的参数。
在这两种情况下,代码都可以通过添加
nested-name-specifier来明确命名模板。第一个可以
使用-fno-access-control;第二个仅被拒绝
with -pedantic。
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屋!