No *_*One 11 c++ pointers enumeration member
我最近尝试创建一个is_class
类,并且需要一种方法让编译器区分枚举类型和定义了转换运算符的类类型.看到类,结构和联合是如何与指针到成员函数兼容的唯一类型,我决定让编译器确定用于实例化is_class
模板的类型是否与指向成员函数的指针兼容.在遇到几个问题之后,我决定在与指向成员的指针一起使用时测试枚举的行为并得到一些古怪的结果.以下部分说明了第一个怪癖:
enum ENUM {};
void Test(void (ENUM::*pmem) (void))
{
/* ... */
}
Test(NULL);
Run Code Online (Sandbox Code Playgroud)
使用Microsoft Visual C++ 2010进行编译时,函数定义的指向成员的部分: (ENUM::*pmem)
以红色突出显示,鼠标悬停在声明上显示错误:
Error: "ENUM" is not a class type
但是,编译器解析此段而不会遇到任何错误,分配pmem
给NULL
.有趣的是,编译器允许这种看法,因为枚举类型不是类,结构或联合,因此不能拥有自己的方法.
第二个兴趣点出现在创建模板函数时,采用其类型不同的指向成员的参数:
template<class _Ty>
void Test_Template(void (_Ty::*pmem) (void))
{
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
当然为了使用这个功能,必须明确限定:
Test_Template<ENUM>(NULL);
Run Code Online (Sandbox Code Playgroud)
但是,此调用会生成错误说明:
invalid explicit template argument(s) for 'void Test(void (__thiscall _Ty::* )(void))'
我通过创建一个额外的函数模板解决了这个问题,该模板的原型将匹配任何未能匹配前模板函数原型的调用(涉及使用省略号).
问题:
为什么枚举与指向成员的指针兼容?
当Test
编译器为模板Test_Template
显式限定生成错误时,为什么在调用非模板函数时存在完全匹配?
关于你的第一个问题,编译器似乎确实报告枚举不能有成员函数,因为编译器报告函数声明错误。它可能通过在内部尝试尽可能多地纠正错误声明来让调用成功,在这种情况下,这意味着注意到您正在尝试声明类似指针的内容并允许调用。编译器并不要求该行给出错误;由于该程序是 I'll 形成的,只要编译器通过诊断拒绝该程序,就不需要到处给出错误。
至于你的第二个问题,拥有第二个模板使错误消失的原因是“替换失败不是错误”(SFINAE)原则。当编译器使用某些类型参数实例化函数模板时,如果它发现特定函数实例化无效(例如,尝试获取指向枚举成员的指针),它不会报告错误。相反,它只是将该模板从考虑中删除。但是,如果您编写的模板在使用给定参数实例化时均无效,则编译器将发出错误,因为它无法找到与您尝试执行的操作匹配的内容。在第一种情况下,当您只有一个模板时,会发生错误,因为 SFINAE 排除了唯一的候选模板,导致模板实例没有匹配的模板。在第二种情况下,你的“catch-all”模板在实例化模板后仍然有效,因此虽然排除了带有成员指针的模板,但仍然有一个合法的模板可以引用。因此,代码完全没问题。