Я хотел посчитать 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.
Чтобы избежать ошибки, поместите второй возврат явно в ветку 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>();
}
}
Rational:
Во время создания экземпляра шаблона вмещающей функции или общей лямбды, если преобразованное условие истинно и инструкция включает в себя подстановку constexpr else, то это подстанция не создается.
http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
Он ничего не говорит о свободном блоке else или блоке, который не должен запускаться, поэтому он создается, вызывая ошибку. (Примечание: также не работает на лязг)
Нет, это не ошибка. Проблема здесь в том, что даже когда 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>();
}