4

可能重复:
在 C++ 中选择重载模板函数时的优先级

模板化函数让我可以方便地操作各种类型:

template<typename T> void destroy(T* obj) {
    delete obj;
}

但在某些时候,我想对类层次结构进行一些专门化:

class Base { virtual void doSomething(); };
class Derived : public Base {};
void destroy(Base* obj) {
    obj->doSomething();
    delete obj;
}

如果我传递了确切的类型,则确实调用了预期的专用函数Base*,但是如果我传递到,重载决议的规则似乎更喜欢通用模板版本,而不是执行静态向上Derived*转换void detroy()

当然,我可以为所有可能的派生类型创建所有重载函数,但它的可维护性较差。

我正在使用 Visual C++ 2008,有没有办法解决上述问题?

4

2 回答 2

5

在所有条件相同的情况下,重载决议更喜欢非模板函数而不是函数模板。但是,在这种情况下,并非所有事物都是平等的。为了匹配您的重载Base*,需要进行派生到基址的指针转换;无需转换即可匹配功能模板。因此,为 选择功能模板Derived*

“简单”,尽管可能容易出错,解决方案是在调用函数之前将您Derived*转换为 a 。Base*

至少在理论上,您可以按照 Ben 的建议采用 SFINAE 方法,但是您必须为您提供专门化的任何类型显式禁用泛型函数模板,否则最终会出现重载歧义。这比显式转换方法更不可维护且更容易出错。(不过,这里的某个人可能知道另一种解决过载歧义的方法;如果有的话,我当然很想知道)。

于 2010-03-07T06:20:48.920 回答
0

没有像 Visual C++ 2009 这样的东西。

您可以使用另一个模板专门化您的函数,并使用 SFINAE 仅匹配 Base 的子类型。但我不知道编译器更喜欢第二个版本的任何原因,通常一个专业化必须以某种方式“更好”才能被选择。

或者,您可以使用 SFINAE 和辅助特征类来防止通用版本匹配 Base 的子类。如果您需要这方面的示例,请询问。

当然,您的专长只会在可见的地方使用。模板函数总是内联的,它们和特化需要在调用者包含的头文件中。

于 2010-03-07T05:40:48.480 回答