参数列表中的模板方法“ = 0”

时间:2019-08-23 00:11:27

标签: c++ c++11

我看到了如下代码:

using EnableIfIntegral = typename std::enable_if<
    std::is_integral<T>::value || std::is_enum<T>::value, int>::type;

template <typename T, EnableIfIntegral<T> = 0>
constexpr int Seconds(T n) {
  return time_internal::FromInt64(n, std::ratio<1>{});
}

template <std::intmax_t N>
constexpr int FromInt64(int64_t v, std::ratio<1, N>) {
  // Do Something
}

我了解模板功能是什么。为什么在模板参数列表中它有SomeClass<T> = 0?我知道T是模板参数。

为什么std::ratio<1, N>是一个参数?

1 个答案:

答案 0 :(得分:2)

我将回答您的两个问题中的第一个。

using EnableIfIntegral = typename std::enable_if<
    std::is_integral<T>::value || std::is_enum<T>::value, int>::type;

我相当确定您不小心遗漏了上一行, 应该是

template<typename T>

所以完整的声明是

template<typename T>
using EnableIfIntegral = typename std::enable_if<
    std::is_integral<T>::value || std::is_enum<T>::value, int>::type;

这是可吞咽的大药丸,稍后我将再讨论此声明的详细信息,但是这里发生的是,如果星星和月亮恰好被倾斜,则变为:< / p>

template<typename T>
using EnableIfIntegral = int;

换句话说,模板类型只是花园品种int的简单别名。仅此而已。移至下一个声明:

template <typename T, EnableIfIntegral<T> = 0>
constexpr int Seconds(T n) {

这简直变成了

template <typename T, int = 0>
constexpr int Seconds(T n) {

换句话说,就是一个简单的模板参数,一个int常量,默认为0。

就是这样,仅此而已。这绝对没有任何作用,而这恰恰是这里的预期结果。

第一个模板参数T从实际参数推导到Seconds()模板函数。然后,第二个模板参数将T模板类型传递给EnableIfIntegral模板别名声明,希望,如果所有的星星和月亮都正确对齐,则不会执行任何操作。

现在,星月何时正确对齐?这是推导的模板类型是某些整数类型或某些enum类型的时候。然后一切都正常。

但是,如果您做一些愚蠢的事情,例如:

std::string what_is_this;

Seconds(what_is_this);

对将要发生的事情的描述非常宽松:Seconds的第一个模板参数推导为std::string。到目前为止,还不错,但是我们已经注定要失败,因为Seconds模板函数中的内容将无法处理std::string值。通常,这通常会导致出现典型的,难以理解的(简直是凡人)C ++编译器错误消息。

但是事情不会走得那么远。首先发生的是推导的T模板参数(现在为std::string)被转发到EnableIfIntegral,并且此模板别名将无法解析。有关所有奇怪的原因,请查阅std::enable_if在您最喜欢的C ++书中的功能。发生这种情况的确切细节不是很重要,关键是Seconds()模板本身的模板替换将失败。编译器将找不到适合此函数调用的Seconds模板。

这种情况通常会从您的编译器产生一条简单得多的错误消息。您的编译器的错误消息将是非常基本的,类似于“嘿,此Seconds模板在这里叫什么?对此我一无所知”。您将看一下代码并意识到“抱歉,我正在传递std::string,但我需要传递一个整数值”。糟糕!

总的来说,这只是一种常见的方法,可以在出现问题且无法编译时减轻使用C ++库的痛苦。没有这个技巧,编译器会抱怨time_internal::FromInt64函数调用(基于问题中显示的代码),但是该函数调用没有问题。问题出在哪里,实际上是无论调用什么Seconds,这种通用方法都可以帮助编译器生成更好的错误消息。