Template base constructor call in member initialization list error
我有一个基本类,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 | template<typename T> class Base { public: Base(int someValue); virtual T someFunc() =0; }; template<typename T> Base<T>::Base(int someValue) {} |
然后是下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include"base.hpp" class Foo : public Base<Foo> { public: Foo(int someValue); virtual Foo someFunc(); }; Foo::Foo(int someValue) : Base(someValue) {} |
号
我从GCC4.2.1中得到以下错误。
1 | error: class ‘Foo’ does not have any field named ‘Base’ |
我应该提到,我的软顶帽盒子上的这个编译很好,运行GCC4.6.2。在我的OS X Lion计算机上编译时发生此错误。
事先谢谢你的帮助。
编辑
问题似乎是我在调用构造函数时没有指示foo类中模板的类型。以下修复了OS X中的错误。
1 | : Base<Foo>(someValue, parent) |
。
编辑
是的,这看起来确实像个虫子。我之前提到的修复了OSX下的错误,并且代码在Fedora中可以通过该修复进行编译。会去看看在OSX中是否有对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:
1
2
3
4
5 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 ]
号
并且
[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:
1
2
3
4
5
6
7
8
9
10 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初始值设定项中不适用,所以我认为这是一个编译器错误。
我的剥离测试用例在GCC 4.1.2和GCC 4.3.4中失败,但是在GCC 4.5.1(C++ 11模式)中成功。这似乎是由GCC bug 189解决的;在GCC 4.5发行说明中:
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提取出来的测试用例:
1 2 3 4 5 6 7 8 | template <typename T> struct Base { }; struct Derived : Base<Derived> { // I love the smell of CRTP in the morning Derived(); }; Derived::Derived() : Base() {}; |