Возможный шаблон & amp; 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(…) заявление.

Итак, вопрос в том, ошибаюсь ли я, и такое поведение следует ожидать, или это ошибка компилятора? Составлено с GCC 7.1.0.

6

Решение

Чтобы избежать ошибки, поместите второй возврат явно в ветку 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

Rational:

Во время создания экземпляра шаблона вмещающей функции или общей лямбды, если преобразованное условие истинно и инструкция включает в себя подстановку constexpr else, то это подстанция не создается.

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

Он ничего не говорит о свободном блоке else или блоке, который не должен запускаться, поэтому он создается, вызывая ошибку. (Примечание: также не работает на лязг)

7

Другие решения

Нет, это не ошибка. Проблема здесь в том, что даже когда 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>();
}
5

По вопросам рекламы [email protected]