Suppose it does something a little more complicated.
constexpr int MeaningOfLife ( int a, int b ) { return a * b; }
const int meaningOfLife = MeaningOfLife( 6, 7 );
Now you have something that can be evaluated down to a constant while maintaining good readability and allowing slightly more complex processing than just setting a constant to a number.
It basically provides a good aid to maintainability as it becomes more obvious what you are doing. Take max( a, b )
for example:
template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }
Its a pretty simple choice there but it does mean that if you call max
with constant values it is explicitly calculated at compile time and not at runtime.
Another good example would be a DegreesToRadians
function. Everyone finds degrees easier to read than radians. While you may know that 180 degrees is 3.14159265 (Pi) in radians it is much clearer written as follows:
const float oneeighty = DegreesToRadians( 180.0f );
Lots of good info here:
http://en.cppreference.com/w/cpp/language/constexpr
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).
Best Answer
It won't bother the compiler. The compiler will (or should anyway) give you a diagnostic when/if you use it on code that doesn't fit the requirements of a
constexpr
.At the same time, I'd be a bit hesitant to just slap it on there because you could. Even though it doesn't/won't bother the compiler, your primary audience is other people reading the code. At least IMO, you should use
constexpr
to convey a fairly specific meaning to them, and just slapping it on other expressions because you can will be misleading. I think it would be fair for a reader to wonder what was going on with a function that's marked as aconstexpr
, but only used as a normal run-time function.At the same time, if you have a function that you honestly expect to use at compile time, and you just haven't used it that way yet, marking it as
constexpr
might make considerably more sense.