Как заставить SFINAE работать с шаблонными специализациями? - PullRequest
2 голосов
/ 04 июня 2019

У меня есть метод шаблона foo.Я хотел бы иметь несколько различных реализаций: для T, vector<T> и vector<vector<T>>, где T - это встроенный тип или некоторый сложный класс.Я хотел бы использовать SFINAE для разделения реализаций для встроенных типов и классов и ограничения набора допустимых типов.

Следующий код работает правильно, но я получаю предупреждающие сообщения:

8:37: warning: inline function 'constexpr bool isType() [with T =
 std::vector<int>]' used but never defined

8:37: warning: inline function 'constexpr bool isType() [with T =
 std::vector<std::vector<int> >]' used but never defined
#include <type_traits>
#include <vector>

using namespace std;

class ComplexClass{};

template<typename T> constexpr bool isType();
template<> constexpr bool isType<int>()  {return true;}
template<> constexpr bool isType<ComplexClass>() {return false;}

template <typename T>
inline typename enable_if<isType<T>(), void>::type
foo(T& value) {}

template <typename T>
inline typename enable_if<!isType<T>(), void>::type
foo(T& value) {}

template <typename T>
inline typename enable_if<isType<T>(), void>::type
foo(vector<T>& value) {}

template <typename T>
inline typename enable_if<isType<T>(), void>::type
foo(vector<vector<T>>& value) {}

int main()
{
    int a;
    vector<int> b;
    vector<vector<int>> c;
    ComplexClass d;
    char e;
    foo(a);
    foo(b);
    foo(c);
    foo(d);
//    foo(e); // has to lead to an error
    return 0;
}

Похоже, что компилятор пытается передать vector<...> в первый enable_if метод и завершается неудачно.Но было бы здорово пропустить такие методы, потому что у нас есть лучшие кандидаты на vector<T> и vector<vector<T>>.Можно ли это сделать?

Ответы [ 2 ]

1 голос
/ 04 июня 2019

Похоже, что вы хотите ограничить шаблоны перегруженных вектором функций, чтобы они могли принимать векторы только встроенных типов.В противном случае эти перегрузки не требуют SFINAE.

Вы также можете использовать std::is_fundamental для обнаружения встроенных типов:

Рабочий пример:

using namespace std;

class ComplexClass {};

template <typename T>
typename enable_if<is_fundamental<T>::value>::type
foo(T& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename T>
typename enable_if<!is_fundamental<T>::value>::type
foo(T& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename T>
typename enable_if<is_fundamental<T>::value>::type
foo(vector<T>& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename T>
typename enable_if<is_fundamental<T>::value>::type
foo(vector<vector<T>>& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

int main() {
    int a;
    vector<int> b;
    vector<vector<int>> c;
    ComplexClass d;
    char e;
    foo(a);
    foo(b);
    foo(c);
    foo(d);
    foo(e);
}

Вывод:

typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(T&) [with T = int; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(std::vector<_Tp>&) [with T = int; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(std::vector<std::vector<_Tp> >&) [with T = int; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
typename std::enable_if<(! std::is_fundamental<_Tp>::value)>::type foo(T&) [with T = ComplexClass; typename std::enable_if<(! std::is_fundamental<_Tp>::value)>::type = void]
typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(T&) [with T = char; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
0 голосов
/ 04 июня 2019

С

template <typename T> constexpr bool isType();
template <> constexpr bool isType<int>()  {return true;}
template <> constexpr bool isType<ComplexClass>() {return false;}

isType<char> существует, даже если определение отсутствует.

Что вы можете сделать, это delete функция:

template <typename T> constexpr bool isType() = delete;
template <> constexpr bool isType<int>()  {return true;}
template <> constexpr bool isType<ComplexClass>() {return false;}

Нет предупреждений с gcc / clang: Демо

Так что foo(e); по-прежнему не соответствует ни одной перегрузке.

Вместо этого я бы использовал диспетчеризацию тегов:

template <typename T> struct Tag{};
std::true_type isType(tag<int>);
std::false_type isType(tag<ComplexClass>);

Демо

...