SFINAE не удается с параметром шаблона Enum
Вопрос
Может кто-то объяснить следующее поведение (я использую Visual Studio 2010).
Заголовок:
#pragma once
#include <boost\utility\enable_if.hpp>
using boost::enable_if_c;
enum WeekDay {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
template<WeekDay DAY>
typename enable_if_c< DAY==SUNDAY, bool >::type goToWork() {return false;}
template<WeekDay DAY>
typename enable_if_c< DAY!=SUNDAY, bool >::type goToWork() {return true;}
источник:
bool b = goToWork<MONDAY>();
Компилятор это дает
error C2770: invalid explicit template argument(s) for 'enable_if_c<DAY!=6,bool>::type goToWork(void)'
а также
error C2770: invalid explicit template argument(s) for 'enable_if_c<DAY==6,bool>::type goToWork(void)'
Но если я изменим параметр шаблона функции в будний день типа Enum для INT, он компилируется нормально:
template<int DAY>
typename enable_if_c< DAY==SUNDAY, bool >::type goToWork() {return false;}
template<int DAY>
typename enable_if_c< DAY!=SUNDAY, bool >::type goToWork() {return true;}
Также нормальная специализация шаблона функций работает нормально, нет удрств там:
template<WeekDay DAY> bool goToWork() {return true;}
template<> bool goToWork<SUNDAY>() {return false;}
Чтобы сделать вещи даже Weirder, если я изменим исходный файл, чтобы использовать любой другой выходний, чем в понедельник или вторник, то есть bool b = goToWork<THURSDAY>();
Ошибка изменяется на это:
error C2440: 'specialization' : cannot convert from 'int' to 'const WeekDay'
Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)
Редактировать: Может быть, кто-то может проверить это с другим компилятором (кроме Visual Studio 2010), чтобы увидеть, будет ли одно и то же самое, потому что это не имеет никакого смысла
Редактировать: Я нашел новый «интересный» аспект такого поведения. То есть если я изменив прямое сравнение параметра шаблона с ==
а также !=
Операторы в сравнении с шаблоном структуры помощника, он работает нормально:
template<WeekDay DAY>
struct Is
{
static const bool Sunday = false;
};
template<>
struct Is<SUNDAY>
{
static const bool Sunday = true;
};
template<WeekDay DAY>
typename enable_if_c< Is<DAY>::Sunday, bool >::type goToWork() {return false;}
template<WeekDay DAY>
typename enable_if_c< !Is<DAY>::Sunday, bool >::type goToWork() {return true;}
Редактировать: Кстати, я сделал отчет об ошибках, и это ответ от Microsoft: «Это ошибка, которая проявляется при попытке продвижения параметра шаблона не типа. К сожалению, учитывая наши ограничения ресурсов для этого выпуска и что работа -Around доступно, мы не сможем это исправить в следующем выпуске Visual Studio. Работа - вокруг - это изменить тип параметра шаблона в INT ».
(Я думаю, что «этот релиз» относится к Visual Studio 2010)
Решение
Работает нормально в GCC 4.2.1.
Похоже, либо шаблон шаблона VC, отсутствует операторы сравнения для типов Enum, или он небрежно преобразовал Enum int, а затем решил быть строгим и запретить неявное преобразование в int (по-видимому, с исключением для 0 и 1).