std::chrono::duration::operator+=中所述,签名为

duration& operator*=(const rep& rhs);

这让我感到奇怪。我假设可以像其他任何内置函数一样使用持续时间文字,但事实并非如此。
#include <chrono>
#include <iostream>

int main()
{
    using namespace std::chrono_literals;
    auto m = 10min;
    m *= 1.5f;
    std::cout << " 150% of 10min: " << m.count() << "min" << std::endl;

    int i = 10;
    i *= 1.5f;
    std::cout << " 150% of 10: " << i << std::endl;
}

输出为
150% of 10min: 10min
150% of 10: 15

为什么以这种方式选择接口(interface)?在我看来,像
template<typename T>
duration& operator*=(const T& rhs);

会产生更直观的结果。

编辑:
感谢您的答复,我知道实现的行为方式以及如何处理它。我的问题是,为什么要这样设计。

我希望转换为int会在操作结束时进行。在下面的示例中,在发生乘法之前,两个操作数都被提升为两倍。 4.5的中间结果随后转换为int,因此结果为4。
int i = 3;
i *= 1.5;
assert(i == 4);

我对std::duration的期望是它的行为方式相同。

最佳答案



之所以这样设计(具有讽刺意味的是),是因为基于积分的计算旨在提供准确的结果,或者不进行编译。但是,在这种情况下,<chrono>库无法控制在绑定(bind)到参数之前将哪些转换应用于参数。

作为一个具体示例,请考虑将m初始化为11min的情况,并假定我们根据您的建议使用了模板化的operator*=。确切的答案现在是16.5min,但是基于整数的chrono::minutes类型无法表示该值。

更好的设计是拥有以下这一行:

m *= 1.5f;  // compile-time error

不编译。这将使库更加自洽:基于积分的算法要么是精确的(或需要duration_cast),要么不进行编译。这将是可能实现的,而为什么未做到这一点的答案仅仅是我没有想到这一点。

如果您(或其他任何人)对此有足够的信心,可以尝试对上述声明的编译时错误进行标准化,那么我愿意在委员会中赞成这种建议。

这项工作将涉及:
  • 具有单元测试的实现。
  • 对其进行配置,以了解它将破坏多少代码,并确保它不会破坏非预期的代码。
  • 编写论文并将其提交给针对C++ 23的C++委员会(现在针对C++ 20为时已晚)。

  • 最简单的方法是从开源实现开始,例如gcc的libstdc++或llvm的libc++。

    10-04 14:29