Hir*_*aCC 9 c++ templates ambiguous ambiguous-call template-argument-deduction
我正在做一些看起来像这样的包装器:
#include <iostream>
template<class T, class Value>
void Apply(void (T::*cb)(Value), T* obj, Value v)
{
(obj->*cb)(v);
}
class Foo
{
public:
void MyFunc(const int& i)
{
std::cout << i << std::endl;
}
const int& GetValue()
{
return i_;
}
private:
int i_ = 14;
};
int main()
{
Foo f;
Apply(&Foo::MyFunc, &f, f.GetValue());
}
Run Code Online (Sandbox Code Playgroud)
我收到这个错误:
Apply
:找不到匹配的重载函数. void Apply(void (__thiscall T::* )(Value),T *,Value)
:模板参数Value
不明确,可能是int
或const int &
. void Apply(void (__thiscall T::* )(Value),T *,Value)
:无法推断Value
from的模板参数const int
. 所以我得到它来自模板参数推导,但我不明白如何.为什么Value
不评估const int&
两次?
Bar*_*rry 13
目前,模板参数Value
在调用中的两个不同位置推导出Apply
:从指针到成员函数参数和从最后一个参数.从&Foo::MyFunc
,Value
推断为int const&
.从f.GetValue()
,Value
推断为int
.这是因为为了模板推断而删除了引用和顶级cv限定符.由于参数的这两个推论Value
不同,因此推论失败 - Apply()
从过载集中删除,因此我们没有可行的过载.
问题是Value
在两个不同的地方推断出来,所以让我们来防止这种情况发生.一种方法是在非推导的上下文中包含其中一个用法:
template <class T> struct non_deduced { using type = T; };
template <class T> using non_deduced_t = typename non_deduced<T>::type;
template<class T, class Value>
void Apply(void (T::*cb)(Value), T* obj, non_deduced_t<Value> v)
{
(obj->*cb)(v);
}
Run Code Online (Sandbox Code Playgroud)
最后一个参数v
是类型non_deduced_t<Value>
,顾名思义,它是一个非推导的上下文.因此,在模板推导过程中,从指向成员函数的指针(如前所述)Value
推导出来int const&
,现在我们只需将其插入到类型中即可v
.
或者,您可以选择推导cb
为自己的模板参数.在这一点上Apply()
只减少到std::invoke()
.