я просто использовал SFINAE для выбора шаблонов функций, когда я имел славную идею инкапсулировать std::enable_if
в структуры, как этотC++: Попытка инкапсулировать зЬй :: enable_if в классе
template<typename T, typename U>
struct EnableWhenEqual
{
typedef typename std::enable_if<std::is_same<T, U>::value>::type type;
};
, а затем использовать его для Например, как этот
template<typename T, typename U, typename Enable = EnableWhenEqual<T,U>::type >
void foo(T&& t, U&& u)
{
if (std::is_same<T,U>::value)
std::cout << "OK, overload allowed." << std::endl;
else
std::cout << "Bad. Should not compile!" << std::endl;
}
Однако, это не работает, так как один видит, вызывая
foo(1,1); //prints "OK, overload allowed"
foo(1,2.0); //prints "Bad, should not compile", but obviously does
С другой стороны, пытаясь создать
EnableWhenEqual<int,int>(); //compiles
EnableWhenEqual<int,double>(); //does not compile because type does not exist
получается ошибка компилятора («тип не является членом станд :: enable_if»).
В чем причина такого поведения? Я спрашиваю, потому что из моего небольшого знания SFINAE я бы подумал, что ошибка в выводе типа приводит к исключению перегрузки ...?
Для полноты вышеуказанная проблема может быть решена с помощью шаблона ступенчатость
template <typename T, typename U>
using EnableWhenEqual = typename std::enable_if<std::is_same<T,U>::value>::type;
Есть и альтернатива использования на структуру вместо шаблона псевдоним?
EDIT: Здесь я имею в виду реализацию, которая решает общую проблему. Например, это здесь
template<typename T, typename U, bool B, typename C=void>
struct EnableWhenEqual {};
template<typename T, typename U, typename C>
struct EnableWhenEqual<T,U,std::is_same<T,U>::value>
{
typedef typename C type;
};
не работает для меня, потому что для частичной специализации нужен простой идентификатор. Если бы это было возможно, можно было бы заменить std::is_same
на общие структуры Condition<T,U>
. Любые альтернативы?
Поскольку вы не указали 'typename' перед аргументом' EnableWhenEqual' по умолчанию, я предполагаю, что вы используете версию VS старше 2013 года. Когда вы добавите 'typename', ваш код [не скомпилируется] (http://coliru.stacked-crooked.com/a/b2c296e2d8de0ec0) как на gcc, так и на clang, а также на VS2013 ('ошибка C2783: 'void foo (T &&, U &&)': не удалось вывести аргумент шаблона для 'Enable'') – Praetorian
Использование 'EnableWhenEqual :: type' требует создания экземпляра' EnableWhenEqual', что приводит к созданию экземпляров всех объявлений участников. Член typedef иногда не является законным, но эта ошибка не возникает в непосредственном контексте шаблона функции 'foo' (SFINAE == SFITICINAE = Ошибка замещения в непосредственном контексте не является ошибкой). –
dyp
Вы можете, конечно, воспроизвести, что делает 'enable_if', т. Е.использование шаблона: 'template struct EnableWhenEqual {}; template struct EnableWhenEqual {using type = void; }; ' –
dyp