编写专用于类及其子类的函数模板

Writing a function template that is specialised for a class and its subclasses

本文关键字:子类 函数模板 专用 用于      更新时间:2023-10-16

我正在尝试编写一个函数模板。一个版本应用于不满足另一个版本条件的所有类型;当参数是给定类的基类或该类本身时,应使用另一个版本。

我尝试过对Base&进行重载,但是当类派生自Base时,它们使用通用的,而不是特定的。

我也尝试过这种SFINAE方法:

struct Base { };
struct Derived : public Base { };
struct Unrelated { };
template<typename T>
void f(const T& a, bool b = true) {
    cout << "not special" << endl;
}
template<typename T>
void f(const Base& t, bool b = is_base_of<Base, T>::value) {
    cout << "special" << endl;
}
Base b;
Derived d;
Unrelated u;
f(b); f(d); f(u);

但他们都打印"不特别"。我不擅长SFINAE,我可能只是做错了。如何编写这样的函数?

首先,这些都不会将"特殊"f称为重载,因为T无法从函数参数中推断出来。 它的第一个参数需要是 T 类型:

void f(const T& t, bool b = is_base_of<Base, T>::value)

完成此操作后,请注意"特殊"重载实际上不会使用 SFINAE 来影响过载分辨率:is_base_of<T, U>::value始终有一个值:它要么是true要么是false。 若要影响重载解析,需要使用 enable_if ,它基于布尔值有条件地定义类型。

此外,两个重载都需要使用 SFINAE:如果T派生自基数(或基数类型),则必须启用"特殊"重载,而"非特殊"重载只有在T不是从基派生时才能启用,否则会出现过载解析歧义。

这两个重载应声明并定义为:

template<typename T>
void f(T const& a, typename enable_if<!is_base_of<Base, T>::value>::type* = 0)
{
    cout << "not special" << endl;
}
template<typename T>
void f(T const& t, typename enable_if<is_base_of<Base, T>::value>::type* = 0)
{
    cout << "special" << endl;
}

最后,请注意,这里没有专业化。 这两个名为 f 的函数是重载

这是一个简单的 C++03 方法:

namespace detail // implementation details, users never invoke these directly
{
    template<bool B>
    struct f_impl
    {
        template<typename T>
        static void f(T const& t) { std::cout << "not specialn"; }
    };
    template<>
    struct f_impl<true>
    {
        static void f(Base const& t) { std::cout << "specialn"; }
    };
}
template<typename T>
void f(T const& t)
{
    detail::f_impl<is_base_of<Base, T>::value>::f(t);
}

现场演示。

使用重载执行此操作的一种方法是这样的:

#include <iostream>
using namespace std;
struct Base { };
struct Derived : public Base { };
struct Unrelated { };
void f(...) {
    cout << "not special" << endl;
}
void f(const Base& t) {
    cout << "special" << endl;
}
int main(){ 
    Base b;
    Derived d;
    Unrelated u;
    f(b); 
    f(d);
    f(u);
    return 0;
}

结果:

special
special
not special

采用变量参数列表的重载将采用任何类型的参数,但始终被认为不如任何其他有效的重载合适。