如果我尝试在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'
这是合理的。模板需要obj
和method
的相同类型,但它们并不完全相同。
但是,如果我用这个模板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解析为完全相同的指针到成员函数类型,并导致相同的模板错误。
答案 0 :(得分:3)
原因是在ButtonAction<DELEGATE>::Type
中,DELEGATE
出现在非推导的上下文中 - 编译器无法从中推断出DELEGATE
,因此它不会尝试。因此,演绎仅从第一个参数开始执行,因此它是明确的。
至于为什么DELEGATE
无法在此上下文中推断出来 - 尝试想象这个过程需要做什么:检查ButtonAction<T>
每个可能的类型{{1}并将其嵌套的typedef T
与参数类型进行比较。请注意,有无数种可能的类型。
经验法则是:Type
左侧的所有内容都是非推断的上下文。
答案 1 :(得分:2)
在第二个示例中,method
参数不参与类型扣除,因此DELEGATE
推导为Derived
,&Base::test
隐式转换为{{1} }}