views:

161

answers:

1

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;}
+1  A: 

Works fine in GCC 4.2.1.

Looks like either VC's template engine is missing comparison operators for enum types, or it sloppily converted the enum to int and then decided to be strict and disallow implicit conversion to int (apparently with an exception for 0 and 1).

By the way, the standard (and my Mac) calls for forward slashes, not backslashes, in the pathname.

Potatoswatter
zeroes00