constexpr

Pages: 12
Hi,

Please consider this simple code:

 
  constexpr double square(double x) { return x*x; }


Now we use it this way:

1
2
 double var = 17;
constexpr double max2 = 1.4*square(var);


why is it incorrect, please?
Last edited on
Same reason as here I guess.
http://www.cplusplus.com/forum/beginner/247793/

There's no need to spam the forum with the same basic question.
There's a problem with making a new thread. Sometimes it won't be shown and I think it's not created. Then I need to redo that. Not my problem, but the website's.

Anyway, back to the question:
The function "square" needs a double, we supply that by double var = 17;. Then, the function must give us a constexpr result to be used for the expression max2.
Everything looks harmless and fine. So why should the compiler give an error!? :(
Last edited on
Another problem with the forum is that I can't apply formats for the question! I ought to create it as plain text then step to modify that by using some formats to be read and understood easily! :( :(
I hope someone remedies that problem.
Last edited on
Then, the function must give us a constexpr result to be used for the expression max2.

You are misunderstanding constexpr: when applied to a function, it means "this function may be used in a constant expression". Note the word "may": constexpr is not a guarantee.

In particular, if you call a constexpr function with arguments (like var) that are not also constant expressions, the result will be computed at run-time. Expressions that must be evaluated at run-time are not constant expressions.
Last edited on
if you call a constexpr function with arguments (like var) that are not also constant expressions, the result will be computed at run-time.

It doesn't necessarily mean that it will be computed at runtime. The compiler is free to optimize the code as it like as long as the observable behaviour is the same. What we do know is that the result of square(var) is not a constant expression, because var is not a constant expression, so it cannot be used to initialize a constexpr variable.
Yes, thank you.
When I make the var a constexpr double, the code works well.
But despite consts and changable variables why do we need constexprs? That is, where are they useful please?
Last edited on
constexpr means that something can be evaluated at compile-time.
const means that you are not allowed to modify something.
That is, where are they useful please?
constexpr is useful as a marker to clarify that a function is (always going to be) pure -- both for the compiler and for the programmer.

It is useful wherever computations are required at compile-time (for example, to compute array dimensions).

Beyond that, constexpr has the potential to simplify many especially complex meta-programs. This is to say that it has already been a substantial boon to language experts - i.e., the folks who write your libraries - and it seems like there will continue to be substantial improvements.
Last edited on
constexpr is useful as a marker to clarify that a function is (always going to be) pure

This isn't the case for member functions.
not the case in general:

1
2
3
4
5
int x = 0; // global
constexpr int foo(int y) {
  if (y < 0) x++;
  return y;
}


Now the C++20's consteval functions are another matter.
Last edited on
I tried to say that constexpr can be used to signal that a function is always logically pure. I didn't want to imply that it was guaranteed.

When I write a function whose result depends solely on its arguments, I have been marking it constexpr, (hopefully) barring issues that would make my program ill-formed. That is, I have been making things constexpr even when I do not currently intend for them to be used in a constant expression.

While I understand that the definition of foo() is well-formed, my intuition tells me that applying constexpr to it is a logical error, because its contract should not change depending on the location of the call.

Notice that if I call foo() outside of a constant expression, I can pass any integer, but if I call it (e.g.) in a constant initializer, it is only legal to pass nonnegative values. This is awful, and I would argue that foo() should never have been marked constexpr in the first place.

I've been using constexpr to denote "pure function". Is this a mistake? Should I be more conservative?
Last edited on
Since "any attribute-token that is not recognised by the implementation is ignored" (C++17),
a custom attribute could be used to mark pure functions.

1
2
3
#include <cmath>

[[marker::pure]] double factorial( unsigned int n )  { return std::tgamma( double(n) - 1 ) ; }


As a bonus , we can also mark non-inlineable pure functions.
A custom attribute could be used to mark pure functions.

On GCC at least, there's already attributes [[gnu::pure]] and [[gnu::const]]:
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
I've been using constexpr to denote "pure function". Is this a mistake? Should I be more conservative?

That might have been the initial intention, but at the moment I think "pure" is a stronger promise than what consexpr functions are supposed to be.

In C++11 constexpr implied const for member functions. This was later changed. Constexpr member functions are now allowed to modify data members of the object that the function is called on which is necessary in order to be able to call non-const member functions on objects inside constexpr functions.

In C++20 std::swap will be marked constexpr. It's obviously not a pure function, because it modifies its arguments, but it is still a useful function to be able to use in constexpr functions.
The Core Guidelines [F.4] (and again at [F.8])
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f4-if-a-function-may-have-to-be-evaluated-at-compile-time-declare-it-constexpr
has
CppCoreGuidelines wrote:
constexpr functions are pure: they can have no side effects.

Which is clearly wrong. I've made a note and will open an issue either tomorrow (Saturday the 29th) or Sunday. If it doesn't exist already, perhaps I'll suggest a guideline against functions like foo().

Anyway, I digress. I agree with you, @Peter - since the constexpr evaluator is stateful, it cannot imply "pure", even at compile-time. (Maybe it did in 2011 - sorry, @frek.) But, perhaps the claim is backwards: If "pure" is stronger than constexpr, should I mark pure functions constexpr when reasonable?

Since there are lots of extra concerns about whether or not it's okay to mark something constexpr, I imagine the answer is "maybe". If this is the case, at best, constexpr can be considered a hint - "this function is maybe pure".
Last edited on
So,

int var = 6*6*6;
Is this computed runtime whereas

constexpr int var = 6*6*6;
is computed compiletime?

Second snippet is preferred?

Are templates and constexpr the only time you can have compiletime computations?
Last edited on
So,

int var = 6*6*6;
Is this computed runtime whereas

Not so simple.

Here, you can see that the calculation is done at compile time:
https://godbolt.org/z/XaWVLC

So is there difference between

const int var = 6*6*6;
and
constexpr int var 6*6*6;

I would appreciate an example.
const and constexpr are messages to the compiler.

In the finished, compiled code, const does not exist. constexpr does not exist. They are just messages to the compiler.

const says to the compiler "while you're making the output executable or library, if you see anything that tries to change this value (after the value has been initialised), that's an error and you are to stop compiling and tell me".

constexpr says to the compiler "this is const, but also, this is something that can be evaluated at compile time - if that's helpful to you, great, if not, also fine".

It is possible to have a const value that can NOT be evaluated at compile time; every constexpr variable is const, but not every const variable is constexpr

The above is... a bit rough, and applies to variables rather than functions (since that's what we're talking about).
Last edited on
Pages: 12