可能的模板& constexpr - 如果不兼容

时间:2017-07-31 20:06:13

标签: c++ templates constexpr if-constexpr

我想在编译时计算e值(不用担心,不是作业),但出了点问题。

template<size_t limit = 3, class result = std::ratio<0, 1>, size_t factorial = 1, size_t count = 1>
constexpr double e_impl() {
    if constexpr(limit == 0) {
        return static_cast<double>(result{}.num) / result{}.den;
    }
    return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>();
}

虽然计算值正确,但编译器会抛出有关模板溢出的错误。似乎limit变量超出范围(低于0),但它不应该发生,因为0 - 案例由if constexpr(…)语句处理。< / p>

所以问题是,我错了,应该预期这种行为,还是编译错误?用GCC 7.1.0编译。

2 个答案:

答案 0 :(得分:7)

为避免错误,请将第二个返回显式放入else分支:

template<size_t limit = 3, class result = std::ratio<0, 1>, size_t factorial = 1, size_t count = 1>
constexpr double e_impl() {
    if constexpr(limit == 0) {
        return static_cast<double>(result{}.num) / result{}.den;
    }
    else
    {
      return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>();
    }
}

https://godbolt.org/g/PdV7m7

理性:

  

在封闭函数模板或通用lambda的实例化期间,如果转换条件为true且语句包含constexpr else子语句,则该子语句不会被实例化。

http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html

它没有说明一个无约束的else块,或者一个不应该运行的块,因此它被实例化,抛出错误。 (注意:铿锵声也失败了)

答案 1 :(得分:5)

不,这不是错误。这里的问题是,即使limit0并且您停止递归,编译器仍然会标记

return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>();

因为它是无条件的。你需要将它放入一个else块,以便在limit不是0时进行编译。

template<size_t limit = 3, class result = std::ratio<0, 1>, size_t factorial = 1, size_t count = 1>
constexpr double e_impl() {
    if constexpr(limit == 0)
        return static_cast<double>(result{}.num) / result{}.den;
    else
        return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>();
}