模板形参有二义性:无法推断模板实参
Template parameter is ambiguous: could not deduce template argument
我正在做一些包装,看起来像这样:
#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());
}
我得到这个错误:
-
Apply
:没有找到匹配的重载函数。 -
void Apply(void (__thiscall T::* )(Value),T *,Value)
:模板参数Value
有歧义,可以是int
或const int &
。 -
void Apply(void (__thiscall T::* )(Value),T *,Value)
:无法从const int
中推断出Value
的模板参数。
所以我得到它,它来自模板参数演绎,但我不明白如何。为什么Value
不两次都求值为const int&
?
为什么失败
目前,模板形参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);
}
最后一个参数v
的类型是non_deduced_t<Value>
,顾名思义,这是一个非推导的上下文。因此,在模板推导过程中,Value
从指向成员函数的指针推导为int const&
(与之前一样),现在我们只需将其插入v
的类型中。
或者,您可以选择将cb
推断为它自己的模板参数。此时,Apply()
就变成了std::invoke()
。
表达式f.GetValue()
是类型为const int
的左值。当它通过值传递时,模板参数推导会推导类型int
。一般来说,从Value v
推导Value
, 将永远不会产生具有顶级cv-限定符的引用或类型。
你可能想用两个单独的模板参数来代替Value
(一个用于函数类型的参数,一个用于实际参数类型),当cb
不能被v
调用时,使用SFINAE来禁用Apply
(或static_assert
用于硬错误)。
- 非类型引用形参/实参
- 哪种方法更适合为函数提供编译时间常数?函数实参与模板形参
- 传递boost::函数,该函数接受一个模板实参作为默认为NULL的形参
- 当实参是初始化列表而形参是引用时,重载解析
- 使用模板模板形参时,模板实参推导失败
- 为什么模板非类型形参指针和引用实参需要是全局的
- 将函数形参的实参解包到c++模板类
- 从模板实参的子类中推断函数模板形参
- 如何将实参传递给此形参
- 带默认模板实参的形参包
- c++函数中理论上可以作为形参传递多少个实参
- 在c++中真的不可能跳过带有默认实参的模板形参吗?为什么语法不这么认为?
- c++默认实参值使用另一个形参的值
- 在模板中使用模板形参作为实参
- 将非const引用使用auto-keyword声明的lambda作为实参传递给std::函数形参类型
- 模板继承:没有依赖模板形参的实参
- 通过函数实参而不是模板形参获取元组的元素
- 基于模板形参的Enum实参
- 在函数实参中使用模板形参不适用gcc4.8
- 函数指针的形参类型的模板实参演绎涉及未演绎的形参包