2

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

4

5 回答 5

9

问题是 C++ 没有完整的 Hindley-Milner 推导算法。相反,它从函数 arguments推导出模板参数。

您的函数没有参数,因此不能推导出模板参数。

于 2013-10-17T11:17:34.230 回答
4

模板参数推导仅适用于函数参数,而不适用于返回类型。这类似,因为您不能在其返回类型上重载函数(原因很简单,您可以不使用返回值,并且在这种情况下编译器无法推断出适当的函数)。

于 2013-10-17T11:17:42.260 回答
4

一般来说,函数模板参数只是根据参数中的类型推导出来的。没有争论,没有推论。要解决此问题,您需要让编译器推断转换。像这样的东西,例如:

struct Epsilon
{
    template <typename T>
    operator T() const
    {
        return std::numeric_limits<T>::min();
    }
};

在这种情况下,调用Epsilon实际上创建了一个对象,该对象可以隐式转换为目标类型;推断将在编译器查找转换时进行,而不是在它尝试调用“函数”时进行。

于 2013-10-17T12:00:27.877 回答
1

我不建议你这样做,但如果你真的需要从返回值 epsilon 中推断出类型,你可以这样做:

float epsilon{};
epsilon = Math::Epsilon<decltype(epsilon)>();

可以推导出返回值类型。如果您想避免冗余并使用单个float,您还可以执行以下操作:

auto e = Epsilon<float>();
于 2017-01-13T00:26:35.017 回答
0

您的方法存在根本问题。

返回值不是函数签名的一部分。这意味着只能有一个具有该返回值的函数。

要理解,尝试编译

float epsilon = Math::Epsilon<float>();
int epsilon = Math::Epsilon<int>();

它不起作用,因为这些函数将具有相同的签名。

看看std::numeric_limits在 C++11 中制作一个工作模板。但是不能推导出模板参数,因为它首先必须被评估然后才能被分配。

于 2013-10-17T11:19:12.280 回答