Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble understanding C++14 Relaxed constexpr restrictions

I've came across new C++14 signature for std::max function:

template< class T > 
const T& max( const T& a, const T& b ); // (C++11)

template< class T > 
constexpr const T& max( const T& a, const T& b );// (C++14)

I've read about Relaxed constexpr restrictions proposal for C++14 but I'm still don't understand why this function return value can be constexpr

Example:

std::vector<int> a, b;
//This does not compile but as my understadnding of `constexpr` this should
int array[std::max(a.size(), b.size()]; (1)
//This is trivial use that does compile
int array[std::max(1,2)]; (2)

When calling std::max in (1) constexpr is ignored ?

like image 725
Alejandro Freeman Avatar asked Jul 14 '15 15:07

Alejandro Freeman


People also ask

Does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?

Can constexpr be changed?

A const int var can be dynamically set to a value at runtime and once it is set to that value, it can no longer be changed. A constexpr int var cannot be dynamically set at runtime, but rather, at compile time. And once it is set to that value, it can no longer be changed.

What's the point of constexpr?

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.

Does constexpr take memory?

The alternatives don't have the all of the positives of static constexpr - you're guaranteed compile time processing, type safety, and (potentially) lower usage of memory (constexpr variables don't need to take up memory, they are effectively hard coded unless if possible).


1 Answers

The base issue isn't directly related to relaxed constexpr rules, a constexpr function is only a constant expression if the arguments are constant expressions. In your second case:

int array[std::max(1,2)];

this works because integer literals are indeed constant expressions.

C++11 was more specific in this case, the draft C++11 standard in section 5.19 [expr.const] lays out the cases where a sub-expression is not considered a constant expression and contains the following:

an invocation of a constexpr function with arguments that, when substituted by function invocation substitution (7.1.5), do not produce a constant expression;

in C++14 this paragraph was removed and we have the following exception:

an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor (12.4) [ Note: Overload resolution (13.3) is applied as usual —end note ];

and we have to use the rest of the rules with respect to the arguments(sub-expressions).

In the first case:

int array[std::max(a.size(), b.size()];

std::vector::size is not marked constexpr and so it falls under the above quoted exception.

Also note that in section 7.1.5 [dcl.constexpr] we have the following:

A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in all respects except that a call to a constexpr function can appear in a constant expression.

Passing arguments to a constexpr function that are not constant expressions just means the expression is not available for uses in contexts that require a constant expression.

As dyp points out that std::max was not made constexpr in C++11 due to various issues probably including committee being conservative and limited time, we can see some of the issues involved in N3039. it being forgotten see N3856 which says:

This short paper proposes to make the standard functions min and max constexpr. They were top on the list of motivating cases for al- lowing reference parameters for constexpr functions in C++11. They were forgotten after the core language change was accepted

For reference we know that 1 and 2 are constant expression from section 5.19 which says:

A literal constant expression is a prvalue core constant expression of literal type, but not pointer type. An integral constant expression is a literal constant expression of integral or unscoped enumeration type. [...]

like image 180
Shafik Yaghmour Avatar answered Oct 13 '22 01:10

Shafik Yaghmour