当我们有 conexpr 值时 <ratio> 有什么用?

What's the use of <ratio> when we have contexpr values?

<ratio> header 允许您使用模板 meta-programming 来处理和操作 rational 值。

然而 - 它是在 C++11 中引入的,当时我们已经有了 constexpr。为什么有一个 fully-constexpr'ifed 库类型用于有理数还不够好,即基本上:

template<typename I>
struct rational { 
    I numerator;
    I denominator;
};

然后改用它?

使用 C++11 constexpr 功能 well-suited 还不够的 std::ratio 是否有一些具体的好处?如果是这样,它在 C++20 中是否仍然相关(constexpr 的扩展“范围”)?

Is there some concrete benefit to using std::ratio that C++11 constexpr functionality would not be well-suited enough for?

您可以将 ratio 作为模板类型参数传递,这就是 std::chrono::duration 的作用。要以 value-based 比率做到这一点,您需要 C++20 或更新版本。

在 C++20 和更新版本中,我看不到当前设计的任何好处。

这里有几个答案和评论,但我认为其中 none 真正说明了 std::ratio 的要点。让我们从 std::ratio 的定义开始。大致相当于:

template<int Num, int Den>
struct ratio {
    static constexpr int num = Num;
    static constexpr int den = Den;
};

虽然您可能可以用作 std::ratio 的替代方法,但如下所示:

template<typename I>
struct ratio {
    I num;
    I den;
};

用一堆 constexpr 函数来执行该类型的算术运算。

请注意,这两个定义之间存在细微但非常重要的区别。而在第二个中,比率的实际值(numden)存储在类型的 实例 中,而在第一个定义中,值是实际上存储在 type 本身。

如果你有一个像 std::chrono 这样的库,你想要一个类型,它可以将时间存储为毫秒数(例如 std::chrono::milliseconds)。如果您稍后想要将此数字转换为秒,则您不想将转换比率编码到 std::chrono::milliseconds 的实例中,而是编码到类型本身中。这就是为什么 std::chrono 使用第一种形式而不是第二种形式(或简单的浮点值)的原因。

要将数字存储到类型而不是实例中,您需要 non-type template parameter。在 C++20 之前,您只能为 non-type 模板参数使用整数值。尽管如此,为了将合理的转换因子存储在标准库中,指定了 std::ratio class 模板。

在 C++20 中,潮流发生了一点变化,因为您现在可以使用浮点数作为 non-type 模板参数。例如 std::chrono::duration 可以重写为:

template<..., double conversion_factor, ...>
duration {
    ...
};

此 C++20 功能与“constexpr 的扩展范围”无关 你在问题中提到的。编译时间计算不同于在类型本身中存储数值,尽管你需要第一个来做第二个。

使用 std::ratio class 模板(专门)用于将值存储到类型中。

boost::rational was provided about the same time as boost::ratio. However since the later was used by boost::chrono which was in turn used by boost::thread, it was easier to add the whole bunch together to the standard. If one seeks a full-fledged run-time usable rational number class, boost::rational is there. The boost::multiprecision is also available to provide very long integral types as the argument for boost::rational. Regarding the standardization of other parts of boost such as boost::random, it has been a big question to me why boost::rational 尚未添加到标准库中。

此致, 调频