Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible template & constexpr–if incompatibility

I wanted to calculate e value at compile–time (don't worry, not a homework), yet something went wrong.

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>();
}

While calculated values are correct, compiler throws an error about overflow in template. It seems like limit variable goes out of range (below 0), but it shouldn't happen as the 0–case is being handled by the if constexpr(…) statement.

So the question is, am I wrong and that behavior should be expected, or is it a compiler bug? Compiled with GCC 7.1.0.

like image 907
Kamil Koczurek Avatar asked Jul 31 '17 20:07

Kamil Koczurek


People also ask

What is a template form?

A form template is a single file that contains multiple supporting files, such as files that define how controls on the form template should appear, files for graphics that appear on the form template, and programming files that enable custom behaviors in the form template.

How can I create a template?

Open the presentation that you want to save as a template. On the File tab, click Save as Template. In the Save As box, type the name that you want to use for the new template. (Optional) In the Where box, choose a location where the template will be saved.

What is template argument list?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Which is correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.


1 Answers

To avoid the error, put the second return explicitly into the else branch:

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:

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

It says nothing about an unconstrained else block, or a block which is not supposed to run, so it gets instantiated, throwing the error. (Note: also fails on clang)

like image 158
erenon Avatar answered Sep 19 '22 23:09

erenon