Ловля функторов с использованием SFINAE в структуре частичной специализации - PullRequest
2 голосов
/ 24 июля 2010

По какой-то сложной причине я хочу преобразовать любой поддерживаемый тип T (исходя из шаблона) в список типов, которые я выбрал.Для этого я попытался использовать структуру шаблона с именем «Преобразовать».Например:

Convert<short>::type should be int
Convert<int>::type should be int
Convert<char>::type should be int
Convert<float>::type should be double
Convert<double>::type should be double
Convert<const char*>::type should be std::string
Convert<std::string>::type should be std::string
etc.

Вышеуказанное легко реализовать с помощью специализации шаблонов.Но есть один случай, который вызывает проблемы:

Convert<T>::type where T is a functor should be T

Чтобы справиться с этим, я думаю, что я должен использовать SFINAE , но мне не удается заставить его скомпилироваться.

Приведенный ниже код дает мне « частичная специализация не может соответствовать списку аргументов для основного шаблона » (т. Е. Написание «Преобразовать» запрещено):

template<typename T, typename = decltype(&T::operator())>
struct Convert<T>       { typedef T type; };

А вот это дает« параметр шаблона не используется или не выводится при частичной специализации » (т. Е. Он считает, что T не используется):

template<typename T>
struct Convert<typename std::enable_if<std::is_function<typename T::operator()>::value,T>::type>
 { typedef T type; };

Я понятия не имею, что делать, все мои попыткиприведем к одной из двух ошибок, приведенных выше.

РЕДАКТИРОВАТЬ: Я хотел бы поймать другие общие вещи, используя ту же модель, поэтому я не могу просто написать "typedef T type" в неспециализированной структуре.

Спасибо

1 Ответ

2 голосов
/ 24 июля 2010

Я бы предложил вам использовать первый подход, но чтобы он работал, вам придется

Объявление главного шаблона с одним неиспользованным аргументом шаблона:

template <class T, class = void> Convert;

Добавьте параметр void ко всем специализациям шаблона, который вы сейчас используете.

Определите свою «специализацию функтора» следующим образом:

template<typename T, typename std::enable_if<std::is_function<typename T::operator()>::value,void>::type>

Это означает, что вы делаете второй аргумент void, если он является функтором (таким образом, он соответствует аргументу шаблона по умолчанию) или не существует, если это не так.

Кстати, почему вы используете typename в typename T::operator()? AFAIK, operator() не тип.

...