15

在 C++ 中,函数模板特化应该与普通函数完全一样。这是否意味着我可以制作一个虚拟的?

例如:

struct A
{
    template <class T> void f();
    template <> virtual void f<int>() {}
};

struct B : A
{
    template <class T> void f();
    template <> virtual void f<int>() {}
};

int main(int argc, char* argv[])
{
    B b;
    A& a = b;
    a.f<int>();
}

Visual Studio 2005给我以下错误:

致命错误 C1001:编译器发生内部错误。

4

3 回答 3

23

不错的编译器错误。对于这种类型的检查,我总是在回到标准和检查之前回退到Comeau编译器。

用于 ONLINE_EVALUATION_BETA2 的 Comeau C/C++ 4.3.10.1(2008 年 10 月 6 日 11:28:09) 版权所有 1988-2008 Comeau Computing。版权所有。模式:严格错误 C++ C++0x_extensions

“ComeauTest.c”,第 3 行:错误:在函数模板声明模板中不允许使用“virtual” virtual void f(); ^

“ComeauTest.c”,第 10 行:错误:函数模板声明模板中不允许使用“virtual” virtual void f(); ^

现在,正如另一个用户发布的那样,事实是该标准不允许您定义虚拟模板化方法。基本原理是对于所有虚拟方法,必须在 vtable 中保留一个条目。问题是模板方法只有在它们被实例化(使用)时才会被定义。这意味着 vtable 最终将在每个编译单元中具有不同数量的元素,具体取决于对f()的不同类型的不同调用的次数。然后地狱就会升起...

如果您想要的是其参数之一上的模板化函数并且一个特定版本是虚拟的(请注意参数的一部分),您可以这样做:

class Base
{
public:
   template <typename T> void f( T a ) {}
   virtual void f( int a ) { std::cout << "base" << std::endl; }
};
class Derived : public Base
{
public:
   virtual void f( int a ) { std::cout << "derived" << std::endl; }
};
int main()
{
   Derived d;
   Base& b = d;
   b.f( 5 ); // The compiler will prefer the non-templated method and print "derived"
}

如果您希望将其概括为任何类型,那么您就不走运了。考虑另一种类型的委托而不是多态(聚合+委托可能是一种解决方案)。有关手头问题的更多信息将有助于确定解决方案。

于 2009-04-16T18:13:37.110 回答
4

根据http://www.kuzbass.ru:8086/docs/isocpp/template.html ISO/IEC 14882:1998:

-3- 成员函数模板不应是虚拟的。

例子:

template <class T> struct AA {
    template <class C> virtual void g(C);   //  Error
    virtual void f();                       //  OK
};
于 2009-04-16T18:08:47.653 回答
1

正如其他人所指出的,这不是合法代码,因为不能声明成员函数模板virtual

然而,即使是 Visual Studio 2012 也对此感到窒息: Visual Studio 2012 上的 C++ 内部编译器错误 单击此处查看完整尺寸

事件日志表明编译器在0xC0000005或上崩溃STATUS_ACCESS_VIOLATION。有趣的是,某个(非法)代码构造如何使编译器出现段错误......

于 2012-11-27T11:01:13.347 回答