SFINAE 因枚举模板参数而失败
有人可以解释以下行为(我正在使用 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;}
如果我改变,让事情变得更奇怪源文件使用除星期一或星期二之外的任何其他工作日,即 bool b = goToWork
错误更改为:
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 的答案:“这是尝试提升非类型模板参数时出现的错误。不幸的是,考虑到我们此版本的资源限制以及解决方法可用,我们将无法在 Visual Studio 的下一版本中修复此问题,解决方法是将模板参数类型更改为 int。”
(我认为“此版本”指的是Visual Studio 2010)
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 GCC 4.2.1 中工作正常。
看起来要么 VC 的模板引擎缺少枚举类型的比较运算符,要么它草率地将枚举转换为 int,然后决定严格禁止隐式转换为 int(显然 0 和 1 除外)。
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).