Can someone explain the following behaviour (I'm using Visual Studio 2010).
header:
#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;}
source:
bool b = goToWork<MONDAY>();
compiler this gives
error C2770: invalid explicit template argument(s) for 'enable_if_c<DAY!=6,bool>::type goToWork(void)'
and
error C2770: invalid explicit template argument(s) for 'enable_if_c<DAY==6,bool>::type goToWork(void)'
But if I change the function template parameter from the enum type WeekDay to int, it compiles fine:
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;}
Also the normal function template specialization works fine, no surprises there:
template<WeekDay DAY> bool goToWork() {return true;}
template<> bool goToWork<SUNDAY>() {return false;}
To make things even weirder, if I change the source file to use any other WeekDay than MONDAY or TUESDAY, i.e. bool b = goToWork<THURSDAY>();
the error changes to this:
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)
EDIT: Maybe someone could test this with a different compiler (other than Visual Studio 2010) to see if the same thing happens, because it doesn't seem to make any sense
EDIT: I found a new "interesting" aspect of this behaviour. That is if I change the direct comparison of the template parameter with ==
and !=
operators into a comparison with a helper struct template, it works fine:
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: By the way, I made a bug report and this is the answer from Microsoft: "This is a bug that manifests when attempting to promote the non-type template parameter. Unfortunately, given our resource constraints for this release and that a worked-around is available, we will not be able to fix this in the next release of Visual Studio. The work-around is to change the template parameter type to an int."
(I think "this release" refers to Visual Studio 2010)