为什么编译器不能推导出这个简单函数的模板参数?

时间:2013-10-17 11:12:39

标签: c++ templates

这是一个非常简单的模板问题(我认为对于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是“浮动”,但显然它不能。我在这里没有理解什么?

5 个答案:

答案 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>();