29

假设我有两个类:SerializablePrintable.

因此,接受所有派生类的简单模板函数Printable可能如下所示:

template <class T, class B = Printable, class = typename std::enable_if<std::is_base_of<B,     T>::value>::type>
void print(T value) {
    cout << value << endl;
}

但是,如果我希望它也接受所有派生类,Serializable而我仍然可以控制函数体,这显然行不通:

template <class T, class B = Printable, class = typename std::enable_if<std::is_base_of<B,     T>::value>::type>
void print(T value) {
    cout << value << endl;
}

template <class T, class B = Serializable, class = typename std::enable_if<std::is_base_of<B,     T>::value>::type>
void print(T value) {
    cout << value << endl;
}

// Error: Redefinition of ...

所以我认为这个问题的剩余解决方案是模板专业化。

但我就是想不通,如何结合std::is_base_ofand来专门化模板std::enable_if

我希望有人愿意帮助我!

4

3 回答 3

24

尝试逻辑运算符:

std::enable_if<std::is_base_of<Serializable, T>::value ||
               std::is_base_of<Printable, T>::value>::type

您可以轻松编写可变参数模板,例如:

is_base_of_any<T, Printable, Serialiable, Googlable, Foobarable>::value

例如:

template <typename T, typename ...> struct is_base_of_any : std::true_type {};

template <typename T, typename Head, typename ...Rest>
struct is_base_of_any<T, Head, Rest...>
: std::integral_constant<bool, std::is_base_of<T, Head>::value ||
                               is_base_of_any<T, Rest...>::value>
{ };

如果你想要不同的实现:

template <bool...> struct tag_type {};

template <typename T>
void foo(T, tag_type<true, false>) { }   // for Printable

template <typename T>
void foo(T, tag_type<false, true>) { }   // for Serializable

template <typename T>
void foo(T x)
{
    foo(x, tag_type<std::is_base_of<Printable, T>::value,
                    std::is_base_of<Serializable, T>::value>());
}

最后一个重载(“面向用户”的重载)可能应该具备上述条件enable_if,以免创建过多的重载候选者。

您可能还可以template <typename ...Bases>使用以下标签制作可变参数:

tag_type<std::is_base_of<Bases, T>::value...>
于 2013-06-19T20:36:16.937 回答
23

比 Kerrek 的回答少一点机械,但恐怕不再具有可读性:

template <class T, typename std::enable_if<std::is_base_of<Printable, T>::value>::type* = nullptr>
void print(const T& value) {
    std::cout << "printable(" << &value << ")\n";
}

template <class T, typename std::enable_if<std::is_base_of<Serializable, T>::value>::type* = nullptr>
void print(const T& value) {
    std::cout << "serializable(" << &value << ")\n";
}

在ideone现场观看

于 2013-06-19T20:55:17.090 回答
2

考虑一下:

void print(const Printable& value) {
    cout << value << endl;
}

void print(const Serializable& value) {
    cout << value << endl;
}

自然地,您将operator<<在右侧操作数中适当地调用一个虚拟函数,该函数将执行实际打印。

于 2013-06-19T21:03:19.993 回答