【问题标题】:Why can't the compiler deduce template argument for this simple function?为什么编译器不能为这个简单的函数推导出模板参数?
【发布时间】:2013-10-17 11:12:39
【问题描述】:

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

【问题讨论】:

标签: c++ templates


【解决方案1】:

问题在于 C++ 没有完整的 Hindley-Milner 演绎算法。相反,它从函数参数中推断出模板参数

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

【讨论】:

  • 好的,我现在明白了。谢谢。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 这很有趣。感谢您的提示。
    【解决方案4】:

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

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

    可以推导出返回值类型。如果您想避免冗余并使用单个float,您也可以这样做:

    auto e = Epsilon<float>();
    

    【讨论】:

      【解决方案5】:

      您的方法存在根本问题。

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

      为了理解,尝试编译

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

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

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

      【讨论】:

      • 我试过了,代码在 C++11 上编译和工作得很好(即使没有范围)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 2018-12-09
      相关资源
      最近更新 更多