2014-09-02 2 views
0

я просто использовал 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>. Любые альтернативы?

+3

Поскольку вы не указали 'typename' перед аргументом' EnableWhenEqual' по умолчанию, я предполагаю, что вы используете версию VS старше 2013 года. Когда вы добавите 'typename', ваш код [не скомпилируется] (http://coliru.stacked-crooked.com/a/b2c296e2d8de0ec0) как на gcc, так и на clang, а также на VS2013 ('ошибка C2783: 'void foo (T &&, U &&)': не удалось вывести аргумент шаблона для 'Enable'') – Praetorian

+5

Использование 'EnableWhenEqual :: type' требует создания экземпляра' EnableWhenEqual', что приводит к созданию экземпляров всех объявлений участников. Член typedef иногда не является законным, но эта ошибка не возникает в непосредственном контексте шаблона функции 'foo' (SFINAE == SFITICINAE = Ошибка замещения в непосредственном контексте не является ошибкой). – dyp

+0

Вы можете, конечно, воспроизвести, что делает 'enable_if', т. Е.использование шаблона: 'template struct EnableWhenEqual {}; template struct EnableWhenEqual {using type = void; }; ' – dyp

ответ

2

Другой вид инкапсуляции:

template<class T, class U> 
using EnableWhenEqual_t = typename std::enable_if< std::is_same<T,U>::value >::type; 

template<typename T, typename U, typename Enable = EnableWhenEqual_t<T,U> > 
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; 
} 

ноты, когда вы просите вопросы VS обработки шаблонов, пожалуйста, укажите точную визуальную студийную версию. Поддержка шаблонов VS чрезвычайно изворотлива.

Смежные вопросы