問(wèn)題描述
我有一個(gè)如下所示的基類(lèi):
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 得到以下錯(cuò)誤.
I get the following error from gcc 4.2.1.
錯(cuò)誤:Foo"類(lèi)沒(méi)有任何名為Base"的字段
error: class ‘Foo’ does not have any field named ‘Base’
我應(yīng)該提到這在我運(yùn)行 gcc 4.6.2 的 Fedora 機(jī)器上編譯得很好.在我的 os x Lion 機(jī)器上編譯時(shí)出現(xiàn)此錯(cuò)誤.
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.
編輯
問(wèn)題似乎是我在調(diào)用構(gòu)造函數(shù)時(shí)沒(méi)有在 Foo 類(lèi)中指明模板的類(lèi)型.以下修復(fù)了 os x 中的錯(cuò)誤.
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)
編輯
是的,這確實(shí)看起來(lái)像一個(gè)錯(cuò)誤.我之前提到的修復(fù)了 os x 下的錯(cuò)誤,并且代碼在 Fedora 中通過(guò)該修復(fù)可以正常編譯.去看看os x中g(shù)cc有沒(méi)有更新.
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- 初始化基類(lèi)decltype 表示該基類(lèi)類(lèi)型.
[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
——結(jié)束示例 ]
而且 Base
應(yīng)該是一個(gè)有效的 injected-class-name 在這里的基礎(chǔ)(也就是說(shuō),你可以用它代替 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]:
像普通(非模板)類(lèi)一樣,類(lèi)模板有一個(gè)注入類(lèi)名(第 9 條).injected-class-name 可以用作 template-name 或 type-name. 當(dāng)它與模板參數(shù)列表,作為模板模板參數(shù)的模板參數(shù),或者作為中的最終標(biāo)識(shí)符詳細(xì)類(lèi)型說(shuō)明符在友元類(lèi)模板聲明中,它指的是類(lèi)模板本身.否則,它等價(jià)于 template-name 后跟 template-parameters 包含在 <>
中的類(lèi)模板的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]:
類(lèi)模板或類(lèi)模板特化的 injected-class-name 可以用作template-name 或 type-name 范圍內(nèi)的任何位置.[ 示例:
[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
——結(jié)束示例 ]
我沒(méi)有發(fā)現(xiàn)任何內(nèi)容表明這不適用于 ctor-initializer,所以我認(rèn)為這是一個(gè)編譯器錯(cuò)誤.
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.
我的精簡(jiǎn)測(cè)試用例 在 GCC 4.1.2 中失敗 和 GCC 4.3.4 但在 GCC 4.5.1 (C++11 模式).它似乎由 GCC bug 189 解決;在 GCC 4.5 發(fā)行說(shuō)明中:
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++ 現(xiàn)在實(shí)施 DR 176.以前 G++ 不支持使用模板基類(lèi)的注入類(lèi)名稱(chēng)作為類(lèi)型名稱(chēng),以及名稱(chēng)的查找發(fā)現(xiàn)模板的聲明在封閉范圍.現(xiàn)在查找名稱(chēng)找到注入的類(lèi)名稱(chēng),它可以用作類(lèi)型或模板,具體取決于名稱(chēng)后面是否跟有模板參數(shù)列表.作為一個(gè)此更改的結(jié)果,以前接受的某些代碼可能是格式錯(cuò)誤,因?yàn)?em class="showen">
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
- 注入的類(lèi)名不可訪問(wèn),因?yàn)樗鼇?lái)自私有庫(kù),或者
- 注入的類(lèi)名不能用作模板模板參數(shù)的參數(shù).
在這兩種情況中的任何一種情況下,都可以通過(guò)添加嵌套名稱(chēng)說(shuō)明符顯式命名模板.第一個(gè)可以使用 -fno-access-control 解決;第二個(gè)只被拒絕與-迂腐.
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.
<小時(shí)>
我用 Qt 抽象出來(lái)的精簡(jiǎn)測(cè)試用例:
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() {};
這篇關(guān)于成員初始化列表錯(cuò)誤中的模板基構(gòu)造函數(shù)調(diào)用的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!