为什么在year_month类中使用模板?

Jos*_*rez 22 c++ c++-chrono

在 MSVC chrono 实现中我看到以下代码

    _EXPORT_STD template <int = 0>
_NODISCARD constexpr year_month operator+(const year_month& _Left, const months& _Right) noexcept {
    const auto _Mo  = static_cast<long long>(static_cast<unsigned int>(_Left.month())) + (_Right.count() - 1);
    const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12;
    return year_month{_Left.year() + years{_Div}, month{static_cast<unsigned int>(_Mo - _Div * 12 + 1)}};
}
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下为什么它使用带有未命名参数的模板吗?

BoP*_*BoP 29

您有两个非常相似的重载operator+,最初没有模板

template <int = 0>
constexpr year_month operator+(const year_month& _Left, const months& _Right) noexcept

constexpr year_month operator+(const year_month& _Left, const years& _Right) noexcept
Run Code Online (Sandbox Code Playgroud)

人们发现,如果您有一个可同时转换为months和 的值years,则此处存在歧义。应该选择哪种转换?

通过制作其中一个运算符(虚拟)模板,可以选择非模板(如果可能),因为模板在重载决策中具有较低的优先级。

该标准规定了这个要求有点复杂(我认为是倒退的):

“如果调用者为月份参数提供的参数可转换为年份,则其到年份的隐式转换序列比其到月份的隐式转换序列更差”

因此,如果转换同样好,则应选择非模板。只有当转换为月份更好时,模板才有机会。

(并且该标准没有明确表示必须是模板,但这是实现此要求的一种方式)。

  • 规范之所以采用这种方式,是因为添加多个“years”比添加“months”的实现效率稍高:只需添加到内部“year”字段,而无需触及“month”字段。 (2认同)