C++ GCC/VS2008:模板基类从自身派生时函数调用的不同行为
以下代码适用于Visual Studio 2008,但不适用于GCC/G++4.3.4 20090804。根据C++标准,哪种行为是正确的?< /P>C++ GCC/VS2008:模板基类从自身派生时函数调用的不同行为,c++,visual-studio-2008,inheritance,gcc,templates,C++,Visual Studio 2008,Inheritance,Gcc,Templates,以下代码适用于Visual Studio 2008,但不适用于GCC/G++4.3.4 20090804。根据C++标准,哪种行为是正确的?< /P> template <int N> struct A : A<N-1> {}; template <> struct A<0> {}; struct B : A<1> {}; template <int N> void Func(const A<N> &
template <int N>
struct A : A<N-1> {};
template <>
struct A<0> {};
struct B : A<1> {};
template <int N>
void Func(const A<N> &a) {}
int main()
{
A<1> a; //is derived from A<0>
Func(a); //vs2008: ok, g++: ok
//Comeau: ok
B b; //is derived from A<1>
Func(b); //vs2008: ok, g++: error, no matching function for call to Func(B&)
//Comeau: error: no instance of function template "Func" matches the
// argument list. The argument types that you used are: (B).
return 0;
}
模板
结构A:A{};
模板
结构A{};
结构B:A{};
模板
void Func(常数A&A){}
int main()
{
A;//是从
Func(a);//vs2008:ok,g++:ok
//科莫:好的
B;//是从
Func(b);//vs2008:ok,g++:错误,对Func(b&)的调用没有匹配的函数
//Comeau:错误:没有函数模板“Func”的实例与
//参数列表。您使用的参数类型是:(B)。
返回0;
}
如果我用
void Func(const A&A){std::cout在N3035中进行了一些挖掘之后,我在第14.9.2.1.4节中发现了这一点:
如果p是一个类且p具有形式简单模板id,则转换后的a可以是推导出的a的派生类。同样,如果p是指向形式简单模板id的类的指针,则转换后的a可以是指向推导出的a所指向的派生类的指针
然而,在14.9.2.1.5中,它说:
只有当类型推断失败时,才会考虑这些替代方案。如果它们产生多个可能的推断A,则类型推断失败
情况是这样的:A
和A
都被认为是B
的基类
我想这对Visual Studio来说意味着一个否定(至少,如果当前的标准说的是相同的:读者练习)。在ISO/IEC 14882中,它几乎是相同的(14.8.2.1):
- 如果P是一个类,并且P具有表单模板id,那么a可以是一个
导出的A的导出类。
同样,如果P是指向类的指针
对于表单模板id,A可以是
指向指向的派生类的指针
由A
只有在类型扣除时才考虑这些替代
否则就会失败。如果他们屈服
一个以上的可能推导出一个
类型扣除失败
所以我同意Jan的观点。这里的任何人都不会?也不会使用Comeau Online进行编译。在第二种情况下,您希望N是什么(因为b可以转换为A和A)?我想这只是MSVC++的另一个扩展。@UncleBens,哇,我还没有看到B
也继承了A
!好眼力:)注意直接调用void f(A);void f(A);B;f(B);
将成功,因为A
继承A
,A
被认为是更好的匹配。但是在演绎过程中,这并不重要,正如@UncleBens所说:编译器将产生两个演绎并拒绝模板。是的,您可以调用Func
指定模板参数,它将工作。(例如:Func(b)
)。以这种方式指定的原因是什么?
void Func(const A<0> &a) { std::cout << '0'; }
void Func(const A<1> &a) { std::cout << '1'; }