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

时间:2012-05-01 17:31:29

标签: c++ templates sfinae

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

我曾尝试为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,我可能只是做错了。我怎么写这样的函数?

3 个答案:

答案 0 :(得分:3)

首先,这些都不会调用“特殊”f重载,因为T无法从函数参数中推断出来。它的第一个参数必须是T类型:

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

完成后,请注意“特殊”重载并不真正使用SFINAE来影响重载分辨率:is_base_of<T, U>::value总是有一个值:它是truefalse。要影响重载分辨率,您需要使用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的函数是重载

答案 1 :(得分:2)

这是一个简单的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 special\n"; }
    };

    template<>
    struct f_impl<true>
    {
        static void f(Base const& t) { std::cout << "special\n"; }
    };
}

template<typename T>
void f(T const& t)
{
    detail::f_impl<is_base_of<Base, T>::value>::f(t);
}

Live demo

答案 2 :(得分:0)

重载的一种方法是:

#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

采用变量参数列表的重载将采用任何类型的参数,但总是被认为不适合任何其他可用的重载。