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.
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).
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?
Yes, this is at least true for constexpr functions. It is the reason why implementations are not allowed to choose which standard functions are marked constexpr, the main issue is that users may observe different behaviors via SFINAE. This is documented in LWG issue 2013: Do library implementers have the freedom to add constexpr? which says (emphasis mine):
Some concern expressed when presented to full committee for the vote
to WP status that this issue had been resolved without sufficient
thought of the consequences for diverging library implementations,
as users may use SFINAE to observe different behavior from otherwise identical code. Issue moved back to Review status, and will be
discussed again in Portland with a larger group. Note for Portland:
John Spicer has agreed to represent Core's concerns during any such
discussion within LWG.