Лучший способ специализировать функцию, используя enable_if только для некоторых типов - PullRequest
0 голосов
/ 06 апреля 2020

У меня есть этот код, который специализирует функцию печати для двух типов и возвращает обратно к базовой версии для любых других типов.

У меня вопрос, есть ли способ написать это без необходимости печатать отрицательный регистр для всех специализированных версий в enable_if базовой функции печати?

, т.е. есть ли способ удалить все !std::is_same и при этом иметь однозначную функцию печати?

Любые версии C ++ приветствуются, но будет полезна та, которая работает в c ++ 14.

#include <iostream>

template<typename T, std::enable_if_t<!std::is_same<T, int>::value && !std::is_same<T, double>::value, int> = 42>
void print(T data)
{
    std::cout << "base:" << data << std::endl;
}

template<typename T, std::enable_if_t<std::is_same<T, double>::value, int> = 42>
void print(T data)
{
    std::cout << "double:" << data << std::endl;
}

template<typename T, std::enable_if_t<std::is_same<T, int>::value, int> = 42>
void print(T data)
{
    std::cout << "int:" << data << std::endl;
}

int main()
{
    std::string foo("foo");
    double bar = 1.2;
    int baz = 5;
    print(foo);
    print(bar);
    print(baz);
}

Ответы [ 2 ]

3 голосов
/ 06 апреля 2020

Для вашего случая использования вы можете просто предоставить перегрузки для функции print при необходимости

#include <iostream>

template<typename T> 
void print(T data)
{
    std::cout << "base:" << data << std::endl;
}

void print(double data)
{
    std::cout << "double:" << data << std::endl;
}

void print(int data)
{
    std::cout << "int:" << data << std::endl;
}

Однако, если у вас есть более сложные ограничения на T, то вы не можете специализироваться print без явного указания отрицания ограничений в случае «по умолчанию».

Если у вас есть доступ к c ++ 17, вы можете написать это в одной функции. Обычная логика if-else c означает, что базовый случай запускается только в том случае, если «специализации» - нет. Это позволяет избежать необходимости указывать отрицания.

template<typename T> 
void print(T data)
{
 if constexpr(std::is_same<T, double>{})
   std::cout << "double:" << data << std::endl;
 else if constexpr(std::is_same<T, int>{})
   std::cout << "int:" << data << std::endl;
 else // if not same as int or double
   std::cout << "base:" << data << std::endl;
}
1 голос
/ 06 апреля 2020

Один из способов избежать дополнительных условий - дать приоритет перегрузки между перегрузками:

template <std::size_t N> struct priority_overload : priority_overload<N - 1> {};
template <> struct priority_overload<0>  {}; // Least priority

, а затем

template<typename T>
void print(T data, priority_overload<0>) // fallback
{
    std::cout << "base:" << data << std::endl;
}

template<typename T, std::enable_if_t<condition1<T>::value, int> = 42>
void print(T data, priority_overload<1>)
{
    std::cout << "cond1:" << data << std::endl;
}

template<typename T, std::enable_if_t<condition2<T>::value, int> = 42>
void print(T data, priority_overload<2>)
{
    std::cout << "cond2:" << data << std::endl;
}

template<typename T>
void print(T data)
{
    print(data, priority_overload<10>{});
    // Priority should be greater or equal to the one of possible overloads
}
...