可能的模板和 constexpr——如果不兼容
Possible template & constexpr–if incompatibility
我想在编译时计算 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(…)
语句处理。
所以问题是,我错了吗,这种行为应该是预料之中的,还是编译器错误?使用 GCC 7.1.0 编译。
为避免错误,将第二个 return 显式放入 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>();
}
}
理性:
During an instantiation of the enclosing function template or generic lambda, if the converted condition is true and the statement includes a constexpr else substatement, that substatement is not instantiated.
http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
它没有提到一个不受约束的 else 块,或者一个不应该 运行 的块,所以它被实例化,抛出错误。 (注意:在 clang 上也失败)
不,这不是错误。这里的问题是,即使 limit
是 0
并且您停止递归,编译器仍然会消除
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>();
}
我想在编译时计算 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(…)
语句处理。
所以问题是,我错了吗,这种行为应该是预料之中的,还是编译器错误?使用 GCC 7.1.0 编译。
为避免错误,将第二个 return 显式放入 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>();
}
}
理性:
During an instantiation of the enclosing function template or generic lambda, if the converted condition is true and the statement includes a constexpr else substatement, that substatement is not instantiated.
http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
它没有提到一个不受约束的 else 块,或者一个不应该 运行 的块,所以它被实例化,抛出错误。 (注意:在 clang 上也失败)
不,这不是错误。这里的问题是,即使 limit
是 0
并且您停止递归,编译器仍然会消除
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>();
}