Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling non constexpr function from constexpr allowed in some conditions

Coming from that question: How to build a custom macro that behaves differently when used as constexpr (like assert)?

I wonder why it is possible to call a non constexpr function if it is conditional.

void bla( )
{
    std::cout << "bla called!" << std::endl;
}

constexpr bool check(bool condition)
{
    //bla(); // can not directly be called -> not constexpr! 
    condition ? void (0) : bla(); // compiles and runs even if condition is true or false!

    // if condition is const, it did not compile because it
    // directly force execution of non constexpr function
    true ? void(0): bla(); // also that compiles!, ok, directly evaluated
    //true ? bla(): void(0); // that did not compile;)

    //false ? void(0): bla(); // that did not compile;)
    false ? bla(): void(0); // compiles, ok, directly evaluated

    return 0;
}

int main()
{
    check( false );
    check( true );
}

Can someone explain which rules are given from the standard? As commented from W.F.: If result is used in constexpr term like an template parameter, it fails if condition results in evaluation of non constexpr function.

That makes assert to complain directly while compiling if result is used in constexpr term.

like image 503
Klaus Avatar asked Dec 09 '17 07:12

Klaus


People also ask

Can a constexpr function call a non constexpr function?

A call to a constexpr function produces the same result as a call to an equivalent non- constexpr function , except that a call to a constexpr function can appear in a constant expression. The main function cannot be declared with the constexpr specifier.

Can constexpr throw exception?

Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.

What is a constexpr function?

A constexpr function is a function that can be invoked within a constant expression. A constexpr function must satisfy the following conditions: It is not virtual. Its return type is a literal type. Each of its parameters must be of a literal type.

What does constexpr mean in C++?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.


1 Answers

A constexpr function implies that it is possible to evaluate the value of the function at compile time. Since this is possible for the input true the function is a valid constexpr. Remember that a constexpr function can have an address just as a regular function, it does not need to be compile time, only when used as a compile time function (which you do not in your example).

As mentioned on the constexpr page on cppreference:

A constexpr function must satisfy the following requirements:

  • it must not be virtual
  • its return type must be LiteralType
  • each of its parameters must be LiteralType
  • there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression (for constructors, use in a constant initializer is sufficient) (since C++14). No diagnostic is required for a violation of this bullet. (Emphasis mine)

Your function fulfils all of the above requirements: it is not virtual, it returns a literal type, the parameter is literal. And more interestingly last bullet point: there exists at least one set of argument values for which the function is actually fully compile time. (hence my emphasis of the last bullet)

As W.F. mentioned in the comments, the function can be used compile time, but only for valid inputs, that is, inputs that does not lead to a sub expression that is not compile time constant. So the input true will work, but false will not since it will lead to bla being evaluated.

This is also stated in the standard: §10.1.5.5:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (8.20), or, for a constructor, a constant initializer for some object (6.6.2), the program is ill-formed, no diagnostic required.

constexpr int f(bool b)
{ return b ? throw 0 : 0; }   // OK

constexpr int f() 
{ return f(true); }           // ill-formed, no diagnostic required

See the examples from the standard document in particular.

like image 109
Tommy Andersen Avatar answered Oct 18 '22 01:10

Tommy Andersen