Reputation: 68852
It seems to me that having a "function that always returns 5" is breaking or diluting the meaning of "calling a function". There must be a reason, or a need for this capability or it wouldn't be in C++11. Why is it there?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
It seems to me that if I wrote a function that return a literal value, and I came up to a code-review, someone would tell me, I should then, declare a constant value instead of writing return 5.
Upvotes: 399
Views: 159337
Reputation: 63797
constexpr
was not introduced as a way to tell the implementation that something can be evaluated in a context which requires a constant-expression; conforming implementations has been able to prove this prior to C++11.
Something an implementation cannot prove is the intent of a certain piece of code:
constexpr
?Let's say you are developing a library and realize that you want to be able to calculate the sum of every integer in the interval (0,N]
.
int f(int n) {
return n > 0 ? n + f(n-1) : n;
}
A compiler can easily prove that the above function is callable in a constant-expression if the argument passed is known during translation; but you have not declared this as an intent - it just happened to be the case.
Now someone else comes along, reads your function, does the same analysis as the compiler; "Oh, this function is usable in a constant-expression!", and writes the following piece of code.
T arr[f(10)]; // freakin' magic
You, as a library developer, decide that f
should cache the result when being invoked; who would want to calculate the same set of values over and over?
int func(int n) {
static std::map<int, int> _cached;
if (_cached.find(n) == _cached.end())
_cached[n] = n > 0 ? n + func(n-1) : n;
return _cached[n];
}
By introducing your optimization, you just broke every usage of your function that happened to be in a context where a constant-expression was required.
You never promised that the function was usable in a constant-expression, and without constexpr
there would be no way of providing such promise.
constexpr
?The primary usage of constexpr is to declare intent.
If an entity isn't marked as constexpr
- it was never intended to be used in a constant-expression; and even if it is, we rely on the compiler to diagnose such context (because it disregards our intent).
Upvotes: 205
Reputation: 191
A lot of the responses here seem to have things a bit backwards, and/or are saying the quiet part loud and the loud part quiet. The one key thing to know about constexpr
is this:
// This guarantees only that the value of "MeaningOfLife" can not be changed
// from the value calculated on this line by "complex_initialization()"
// (unless you cast away the const of course, don't do that).
// Critically here, everything happens at *runtime*.
const int MeaningOfLife = complex_initialization(1234, 5678, "hello");
// This guarantees that "MeaningOfLife" is fully evaluated and "initialized"
// *at compile time*. If that is not possible due to complex_initialization()
// not being evaluatable at compile time, the compiler is required to abort
// compilation of the program.
// Critically here, to put a fine point on it, everything happens at
// *compile time*, guaranteed. There won't be a runtime call to
// complex_initialization() at all in the final program.
constexpr int MeaningOfLife = complex_initialization(1234, 5678, "hello");
Note that it's the constexpr
-ness of the left-hand side which forces the guarantees which give constexpr
its reason to exist. It is up to you to make sure the right-hand side can in fact be evaluated at compile time of course, and importantly, just declaring a function constexpr
does not in and of itself do that.
So the answer to your question is that you should declare a variable constexpr
when you need or want its initialization (everything happening on the right-hand side) to be forced to either happen entirely at compile time or break the build.
Upvotes: 3
Reputation: 62323
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
Upvotes: 358
Reputation: 860
When to use constexpr
:
Upvotes: -4
Reputation: 1429
All of the other answers are great, I just want to give a cool example of one thing you can do with constexpr that is amazing. See-Phit (https://github.com/rep-movsd/see-phit/blob/master/seephit.h) is a compile time HTML parser and template engine. This means you can put HTML in and get out a tree that is able to be manipulated. Having the parsing done at compile time can give you a bit of extra performance.
From the github page example:
#include <iostream>
#include "seephit.h"
using namespace std;
int main()
{
constexpr auto parser =
R"*(
<span >
<p color="red" height='10' >{{name}} is a {{profession}} in {{city}}</p >
</span>
)*"_html;
spt::tree spt_tree(parser);
spt::template_dict dct;
dct["name"] = "Mary";
dct["profession"] = "doctor";
dct["city"] = "London";
spt_tree.root.render(cerr, dct);
cerr << endl;
dct["city"] = "New York";
dct["name"] = "John";
dct["profession"] = "janitor";
spt_tree.root.render(cerr, dct);
cerr << endl;
}
Upvotes: 4
Reputation: 59
It's useful for something like
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
int some_arr[MeaningOfLife()];
Tie this in with a traits class or the like and it becomes quite useful.
Upvotes: -4
Reputation: 442
Have just started switching over a project to c++11 and came across a perfectly good situation for constexpr which cleans up alternative methods of performing the same operation. The key point here is that you can only place the function into the array size declaration when it is declared constexpr. There are a number of situations where I can see this being very useful moving forward with the area of code that I am involved in.
constexpr size_t GetMaxIPV4StringLength()
{
return ( sizeof( "255.255.255.255" ) );
}
void SomeIPFunction()
{
char szIPAddress[ GetMaxIPV4StringLength() ];
SomeIPGetFunction( szIPAddress );
}
Upvotes: 8
Reputation: 59269
constexpr
functions are really nice and a great addition to c++. However, you are right in that most of the problems it solves can be inelegantly worked around with macros.
However, one of the uses of constexpr
has no C++03 equivalent, typed constants.
// This is bad for obvious reasons.
#define ONE 1;
// This works most of the time but isn't fully typed.
enum { TWO = 2 };
// This doesn't compile
enum { pi = 3.1415f };
// This is a file local lvalue masquerading as a global
// rvalue. It works most of the time. But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;
// This is a true constant rvalue
constexpr float pi = 3.1415f;
// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor
struct A
{
static const int four = 4;
static const int five = 5;
constexpr int six = 6;
};
int main()
{
&A::four; // linker error
&A::six; // compiler error
// EXTREMELY subtle linker error
int i = rand()? A::four: A::five;
// It not safe use static const class variables with the ternary operator!
}
//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;
Upvotes: 20
Reputation:
From Stroustrup's speech at "Going Native 2012":
template<int M, int K, int S> struct Unit { // a unit in the MKS system
enum { m=M, kg=K, s=S };
};
template<typename Unit> // a magnitude with a unit
struct Value {
double val; // the magnitude
explicit Value(double d) : val(d) {} // construct a Value from a double
};
using Speed = Value<Unit<1,0,-1>>; // meters/second type
using Acceleration = Value<Unit<1,0,-2>>; // meters/second/second type
using Second = Unit<0,0,1>; // unit: sec
using Second2 = Unit<0,0,2>; // unit: second*second
constexpr Value<Second> operator"" s(long double d)
// a f-p literal suffixed by ‘s’
{
return Value<Second> (d);
}
constexpr Value<Second2> operator"" s2(long double d)
// a f-p literal suffixed by ‘s2’
{
return Value<Second2> (d);
}
Speed sp1 = 100m/9.8s; // very fast for a human
Speed sp2 = 100m/9.8s2; // error (m/s2 is acceleration)
Speed sp3 = 100/9.8s; // error (speed is m/s and 100 has no unit)
Acceleration acc = sp1/0.5s; // too fast for a human
Upvotes: 11
Reputation: 72221
There used to be a pattern with metaprogramming:
template<unsigned T>
struct Fact {
enum Enum {
VALUE = Fact<T-1>*T;
};
};
template<>
struct Fact<1u> {
enum Enum {
VALUE = 1;
};
};
// Fact<10>::VALUE is known be a compile-time constant
I believe constexpr
was introduced to let you write such constructs without the need for templates and weird constructs with specialization, SFINAE and stuff - but exactly like you'd write a run-time function, but with the guarantee that the result will be determined in compile-time.
However, note that:
int fact(unsigned n) {
if (n==1) return 1;
return fact(n-1)*n;
}
int main() {
return fact(10);
}
Compile this with g++ -O3
and you'll see that fact(10)
is indeed evaulated at compile-time!
An VLA-aware compiler (so a C compiler in C99 mode or C++ compiler with C99 extensions) may even allow you to do:
int main() {
int tab[fact(10)];
int tab2[std::max(20,30)];
}
But that it's non-standard C++ at the moment - constexpr
looks like a way to combat this (even without VLA, in the above case). And there's still the problem of the need to have "formal" constant expressions as template arguments.
Upvotes: 7
Reputation: 114685
Another use (not yet mentioned) is constexpr
constructors. This allows creating compile time constants which don't have to be initialized during runtime.
const std::complex<double> meaning_of_imagination(0, 42);
Pair that with user defined literals and you have full support for literal user defined classes.
3.14D + 42_i;
Upvotes: 9
Reputation: 22591
It can enable some new optimisations. const
traditionally is a hint for the type system, and cannot be used for optimisation (e.g. a const
member function can const_cast
and modify the object anyway, legally, so const
cannot be trusted for optimisation).
constexpr
means the expression really is constant, provided the inputs to the function are const. Consider:
class MyInterface {
public:
int GetNumber() const = 0;
};
If this is exposed in some other module, the compiler can't trust that GetNumber()
won't return different values each time it's called - even consecutively with no non-const calls in between - because const
could have been cast away in the implementation. (Obviously any programmer who did this ought to be shot, but the language permits it, therefore the compiler must abide by the rules.)
Adding constexpr
:
class MyInterface {
public:
constexpr int GetNumber() const = 0;
};
The compiler can now apply an optimisation where the return value of GetNumber()
is cached and eliminate additional calls to GetNumber()
, because constexpr
is a stronger guarantee that the return value won't change.
Upvotes: 0
Reputation: 146900
Your basic example serves he same argument as that of constants themselves. Why use
static const int x = 5;
int arr[x];
over
int arr[5];
Because it's way more maintainable. Using constexpr is much, much faster to write and read than existing metaprogramming techniques.
Upvotes: 1
Reputation: 545488
Take std::numeric_limits<T>::max()
: for whatever reason, this is a method. constexpr
would be beneficial here.
Another example: you want to declare a C-array (or a std::array
) that is as big as another array. The way to do this at the moment is like so:
int x[10];
int y[sizeof x / sizeof x[0]];
But wouldn’t it be better to be able to write:
int y[size_of(x)];
Thanks to constexpr
, you can:
template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
return N;
}
Upvotes: 95
Reputation: 37433
From what I've read, the need for constexpr comes from an issue in metaprogramming. Trait classes may have constants represented as functions, think: numeric_limits::max(). With constexpr, those types of functions can be used in metaprogramming, or as array bounds, etc etc.
Another example off of the top of my head would be that for class interfaces, you may want derived types define their own constants for some operation.
Edit:
After poking around on SO, it looks like others have come up with some examples of what might be possible with constexprs.
Upvotes: 15