0

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

我尝试过重载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,我可能只是做错了。我怎样才能写出这样的函数?

4

3 回答 3

3

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

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

一旦完成,请注意“特殊”重载并没有真正使用 SFINAE 来影响重载解析: is_base_of<T, U>::value总是有一个值:它是trueor 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重载

于 2012-05-01T17:40:39.420 回答
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);
}

现场演示

于 2012-05-01T17:37:37.987 回答
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

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

于 2012-05-01T17:48:22.617 回答