Ошибка SFINAE с параметром шаблона enum - PullRequest
3 голосов
/ 04 мая 2010

Может кто-нибудь объяснить следующее поведение (я использую 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)'

Но если я изменю параметр шаблона функции с типа перечисления WeekDay на 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;}

Чтобы сделать ситуацию еще более странной, если я изменю исходный файл на использование любого другого WeekDay, кроме MONDAY или TUESDAY, т.е. 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;}

EDIT: Кстати, я сделал отчет об ошибке, и это ответ от Microsoft: «Это ошибка, которая проявляется при попытке продвинуть параметр шаблона нетипичного типа. К сожалению, учитывая наши ограничения ресурсов для этого выпуска и что обойти доступно, мы не сможем это исправить в следующем выпуске Visual Studio. Обходной путь - изменить тип параметра шаблона на int. "

(я думаю, что «этот выпуск» относится к Visual Studio 2010)

1 Ответ

2 голосов
/ 06 мая 2010

Прекрасно работает в GCC 4.2.1.

Похоже, либо в шаблонизаторе VC отсутствуют операторы сравнения для типов enum, либо он небрежно преобразовал enum в int, а затем решил быть строгим и запретил неявное преобразование в int (очевидно, за исключением 0 и 1).

...