Подтвердить что ты не робот

Специализация частичного шаблона С++ в сочетании с std:: is_base_of и std:: enable_if

Скажем, у меня есть два класса: Serializable и Printable.

Таким образом, простая функция шаблона, которая принимает все производные классы 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_of и std::enable_if.

Я надеюсь, что кто-то захочет помочь мне!

4b9b3361

Ответ 1

Попробуйте логический оператор:

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, чтобы не создавать слишком много кандидатов перегрузки.

Возможно, вы также можете сделать varadic template <typename ...Bases> с тегом вроде:

tag_type<std::is_base_of<Bases, T>::value...>

Ответ 2

Немного меньше машин, чем ответ Керрека, но я боюсь, что не читаем:

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

Смотрите жить в идеоне.

Ответ 3

Рассмотрим это:

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

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

Естественно, у вас будет соответствующий operator<< вызов виртуальной функции в правой части операнда, который будет выполнять фактическую печать.