Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can adding 'constexpr' change the behaviour?

Given two programs where the only difference in the source code is the presence or absence of one constexpr, is it possible that the meaning of the program changes?

In other words, if there was a compiler option to ask the compiler to try really hard to infer constexpr where possible, would it break existing standard code and/or change its meaning in bad ways?

Imagine dealing with a codebase where the original developer forgot to include constexpr in places where it was possible, perhaps code written before C++11. It would be great if the compiler would infer constexpr to help you get on with your work. Of course, perhaps it should also warn about each time it does this inference, encouraging you to explicitly add the constexpr later. But it would still be useful. My worry is that it might break things?

So far, the only thing I can think of is that constexpr functions are implicitly inline and there can be situations where adding inline can change things in bad ways; for example if you break the one-definition-rule.

like image 982
Aaron McDaid Avatar asked Sep 04 '15 11:09

Aaron McDaid


People also ask

Should I use constexpr everywhere?

Yes. I believe putting such const ness is always a good practice wherever you can. For example in your class if a given method is not modifying any member then you always tend to put a const keyword in the end.

What is the use 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.

Which is false about constexpr?

Short answer: static_assert(false) should never appear in a constexpr if expression, regardless of whether it's in a template function or whether it's in the discarded branch.

Where do I put constexpr?

In other words, you should use constexpr for your constants in header files, if possible, otherwise const . And if you require the address of that constant to be the same everywhere mark it as inline .


1 Answers

There is an easy trick:

template<int n>struct i{}; int foo(int){return 0;} constexpr int foo(char){return 'a';}  template<class T=int, T x=1,i<foo(x)>* =nullptr> bool bar(){return true;} template<class T=int, T x=1,class...Ts> bool bar(Ts...){return false;} 

if int foo(int) is constexpr, a different overload of bar is chosen by default.

With different code running, any behaviour change can occur.

live example (simply change which #define X is commented out).


Design of the example:

The char overload prevents the above code from being ill-formed, no diagnostic required, as all templates must have a valid specialization. foo<char> supplies that. In practice, its existence is not required: ADL could find a foo from far away, overloaded on a some_type*, then pass some_type* as T. Which means no compilation unit could prove the code was ill-formed.

The Ts... makes that bar overload less-preferred. So if the first one matches, there is no ambiguity. Only if the first one fails to match (due to a SFINAE caused by foo(x) not being constexpr) does the second overload get called (or if, say, someone passed arguments to it).

like image 171
Yakk - Adam Nevraumont Avatar answered Oct 13 '22 18:10

Yakk - Adam Nevraumont