以下 C++ 代码无法在 MS Visual Studio 2010 中编译:
class Foo
{
public:
/// Provides the signature of the methods that can be given to addValueSetListener
template <typename TT>
struct ChangeHandler
{
typedef void ( TT::* OnSetValueMethod )();
};
template <typename TT>
void bar_ok(TT*, void ( TT::* )(), bool = false) {}
template <typename TT>
void bar_ok(const char*, TT*, void ( TT::* )()) {}
template <typename TT>
void bar_fails(TT*, typename ChangeHandler<TT>::OnSetValueMethod, bool = false) {}
template <typename TT>
void bar_fails(const char*, TT*, typename ChangeHandler<TT>::OnSetValueMethod) {}
void testBar() {}
};
int main()
{
Foo foo;
foo.bar_ok ("allo",& foo, & Foo::testBar); // compiles
foo.bar_fails("allo",& foo, & Foo::testBar); // compile ERROR
}
编译器错误是 'TT': must be a class or namespace when followed by '::'
, for the ERROR line.
失败行和未失败行之间的唯一区别是 bar_fails 通过“模板化类型定义”声明“方法指针类型”参数 void (TT::*)()
",而 bar_ok 直接声明它。
请注意,如果没有 const char*
的重载,模板化的 typedef 工作正常。在 const char* 重载可用的情况下,编译器错误地选择了 bar_fails 的 TT=[const char]
重载,但它正确地选择了 bar_ok 的 TT=Foo 重载。当 typedef 用于“简单”数据(如 TT* 或 float*)时,不会出现此问题。
最佳答案
原因是在bar_ok
的情况下,SFINAE可以应用,因为错误的构造 const char::*
出现在模板参数替换的直接上下文中。在 bar_fail
情况下,它被删除了一步(隐藏在“模板类型定义”中),这意味着 SFINAE 不再适用,编译器必须处理 const char::*< 的语法废话
,从而停止并报告错误。
换句话说,并不是编译器在bar_fail
中选择了错误的重载。它必须在两种情况下检查两个过载,但在第一种情况下,SFINAE 允许忽略错误的情况,而在第二种情况下,它“为时已晚”。
关于c++ - 方法指针模板不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18327388/