template<typename T>
bool func(typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x)
T
используется выше в не выводится контексте. Это означает, что он не будет вычитать T
, так как он (в общем случае) требует обращения вспять произвольное преобразование с полным преобразованием, что невозможно.
func
имеет то, что первым аргументом является enum class Bar
, а второй - int
. Из этого вы ожидаете, что он выведет T
.
При установке T
на enum class Bar
действительно ли проблема, C++ не угадывает. Этот шаблон совпадает.
Предположим, что у нас было:
template<class T>
struct blah { using type=int; };
template<>
struct blah<int> { using type=double; };
затем
template<class T>
bool func(typename blah<T>::type);
Если кто-то пропускает int
к func
, какой тип должен быть выведен на T
? Это пример игрушки: foo<T>::type
может выполнить алгоритм Turing-complete для отображения T
типа, о котором идет речь. Инвертирование этого или даже определение того, является ли обратное неоднозначным, в общем случае невозможно. Поэтому C++ даже не пытается даже в простых случаях, так как край между простым и сложным быстро становится нечетким.
Чтобы устранить проблему:
template<class T,class=typename std::enable_if< std::is_enum<T>::value >::type>
bool func(T &t, int x) {
}
Теперь T
используется в выведенного контексте. SFINAE по-прежнему происходит, но не блокирует вычет типа шаблона.
Или вы можете дождаться концепций C++ 1z, которые автоматизируют описанную выше конструкцию (в основном).
Рассматривая связанный вопрос, простой способ решить вашу проблему - отправка меток.
template<typename T>
bool func(T &t, int x)
{
// do stuff...
}
Однако я хотел бы иметь три различных функциональных органов:
У нас есть 3 случая:
T является перечисление
T быть символ без знака
Все остальное
так, отправка:
namespace details {
template<class T>
bool func(T& t, int x, std::true_type /* is_enum */, std::false_type) {
}
template<class T>
bool func(T& t, int x, std::false_type, std::true_type /* unsigned char */) {
}
template<class T>
bool func(T& t, int x, std::false_type, std::false_type) {
// neither
}
}
template<class T>
bool func(T& t, int x) {
return details::func(t, x, std::is_enum<T>{}, std::is_same<unsigned char, T>{});
}
Теперь нормальные правила перегрузки используются, чтобы выбрать между 3 функциями. Если у вас есть тип enum
и unsigned char
(невозможно), вы получите ошибку времени компиляции.
ОК, это что-то.Кажется, что работает и с оберткой: 'template bool func2 (T & t, int x) {return func (t, x); } ' –