这是一个非常简单的模板问题(我认为对于C ++专家来说很简单),涉及制作通用数学函数。我有一个简单的Epsilon函数,如下所示:
template<class T>
static T Epsilon()
{
return std::numeric_limits<T>::Min();
}
我希望将它分配给某个变量,如下所示:
float epsilon = Math::Epsilon();
,唉,我收到了编译错误:
错误C2783:'T Math :: Epsilon(void)':无法推断模板 'T'的论据
我可以像这样分配它,没有错误:
float epsilon = Math::Epsilon<float>();
我认为模板引擎能够看到我的T是“浮动”,但显然它不能。我在这里没有理解什么?
答案 0 :(得分:9)
问题是C ++没有完整的Hindley-Milner演绎算法。相反,它从函数参数中推断出模板参数。
您的函数没有参数,因此无法推导出模板参数。
答案 1 :(得分:4)
模板参数推导仅适用于函数参数,而不适用于返回类型。这是类似的,因为你不能在返回类型上重载函数(原因很简单,你不允许使用返回的值,并且在这种情况下编译器无法推断出相应的函数)。
答案 2 :(得分:4)
通常,功能模板参数仅基于推导 关于参数中的类型。没有争论,没有扣除。至 解决这个问题,你需要让编译器推断出来 转换。像这样的东西,例如:
struct Epsilon
{
template <typename T>
operator T() const
{
return std::numeric_limits<T>::min();
}
};
在这种情况下,对Epsilon
的调用实际上会创建一个对象,
它可以隐式转换为目标类型;该
当编译器查找时,将进行推导
转换,而不是在尝试调用“函数”时。
答案 3 :(得分:1)
您的方法存在根本问题。
返回值不是函数签名的一部分。这意味着只能有一个具有该返回值的函数。
要理解,请尝试编译
float epsilon = Math::Epsilon<float>();
int epsilon = Math::Epsilon<int>();
它不起作用,因为函数具有相同的签名。
查看C ++ 11中的std::numeric_limits
来制作工作模板。但是不能推导出模板参数,因为它首先必须被评估然后才能被分配。
答案 4 :(得分:1)
我不建议你这样做,但是如果你真的需要从返回值epsilon中推断出类型,你可以这样做:
float epsilon{};
epsilon = Math::Epsilon<decltype(epsilon)>();
可以推导出返回值类型。如果您想避免冗余并使用单个float
,您还可以执行以下操作:
auto e = Epsilon<float>();