c++ - 方法指针模板不编译

标签 c++ templates typedef

以下 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/

相关文章:

c - 使用 'typedef' 的正确方法是什么?

c++ - SWIG:公共(public)函数中使用的私有(private) typedef

c++ - C++ 宏可以计算 switch 语句中的案例吗?

c - 包含的结构定义无法识别

c++平均函数无法正常工作

c++ - 当涉及多个模板类型时,是否可以缩小类和函数之间的友元关系?

python - 为什么我的 urls.py 不起作用?

c++ - 使用模板没有开销的派生类?

c++ - Map.erase() 抛出错误,为什么?

c++ - OpenCL 和 std::vector<bool> 不兼容