为什么这个typedef允许我在这个模板中使用基类指针到成员函数?

时间:2014-03-17 21:13:17

标签: c++ templates inheritance typedef

如果我尝试在MSVC中编译以下代码:

template <typename DELEGATE>
void newButton(DELEGATE *obj, int (DELEGATE::*method)(int))
{
    std::function<int(int)> callback = std::bind(
        method, obj, std::placeholders::_1);
    // ...
}

class Base
{
public:
    virtual int test(int f) { return f * f; }
};

class Derived : public Base
{
};

int main()
{
    Derived d;
    newButton(&d, &Base::test);
}

我收到编译错误:

'void newButton(DELEGATE *,int (__thiscall DELEGATE::* )(int))' : 
 template parameter 'DELEGATE' is ambiguous
          could be 'Base'
          or       'Derived'

这是合理的。模板需要objmethod的相同类型,但它们并不完全相同。

但是,如果我用这个模板struct typedef替换指向成员函数的指针,它就会编译!

template <typename DELEGATE>
struct ButtonAction
{
    typedef int (DELEGATE::*Type)(int);
};

template <typename DELEGATE>
void newButton(DELEGATE *obj, typename ButtonAction<DELEGATE>::Type method)
{
    std::function<int(int)> callback = std::bind(
        method, obj, std::placeholders::_1);
    // ...
}

// rest same as before

为什么呢?我原本期望将typedef解析为完全相同的指针到成员函数类型,并导致相同的模板错误。

2 个答案:

答案 0 :(得分:3)

原因是在ButtonAction<DELEGATE>::Type中,DELEGATE出现在非推导的上下文中 - 编译器无法从中推断出DELEGATE,因此它不会尝试。因此,演绎仅从第一个参数开始执行,因此它是明确的。

至于为什么DELEGATE无法在此上下文中推断出来 - 尝试想象这个过程需要做什么:检查ButtonAction<T> 每个可能的类型{{1}并将其嵌套的typedef T与参数类型进行比较。请注意,有无数种可能的类型。

经验法则是:Type左侧的所有内容都是非推断的上下文。

答案 1 :(得分:2)

在第二个示例中,method参数不参与类型扣除,因此DELEGATE推导为Derived&Base::test隐式转换为{{1} }}