【问题标题】:Why does this typedef allow me to use a base class pointer-to-member-function in this template?为什么这个 typedef 允许我在这个模板中使用基类指针到成员函数?
【发布时间】:2014-03-17 21:13:17
【问题描述】:

如果我尝试在 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 具有相同的类型,但它们并不完全相同。

但是,如果我用这个模板结构 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 解析为完全相同的指向成员函数的指针类型,并导致相同的模板错误。

【问题讨论】:

    标签: c++ templates inheritance typedef


    【解决方案1】:

    原因是ButtonAction&lt;DELEGATE&gt;::Type中,DELEGATE出现在非推导上下文中——编译器无法由此推导DELEGATE,所以没有尝试。因此,仅从第一个参数进行推导,因此是明确的。

    至于为什么DELEGATE 不能在这种情况下推导出来——试着想象一下这个过程需要是什么:检查ButtonAction&lt;T&gt; 所有可能的类型T 并比较它的嵌套typedef Type 反对参数类型。请注意,有无数种可能的类型。

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

    【讨论】:

    • 感谢您非常有帮助的回答。但是为什么是“在ButtonAction&lt;DELEGATE&gt;::TypeDELEGATE出现在非推导上下文中——编译器不能由此推导出DELEGATE”?
    • @japreiss 我已经扩展了答案。
    【解决方案2】:

    在第二个例子中,method参数不参与类型推导,所以DELEGATE推导为Derived&amp;Base::test隐式转换为(Derived::*)(int)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 2022-06-14
      • 1970-01-01
      相关资源
      最近更新 更多