gotchacppCritical
What's the difference between constexpr and const?
Viewed 0 times
constandconstexprbetweenthedifferencewhat
Problem
What's the difference between
constexpr and const?- When can I use only one of them?
- When can I use both and how should I choose one?
Solution
Basic meaning and syntax
Both keywords can be used in the declaration of objects as well as functions. The basic difference when applied to objects is this:
-
-
When applied to functions the basic difference is this:
-
-
Constant expressions
As said above,
-
It can be used in places that require compile-time evaluation, for example, template parameters and array-size specifiers:
-
But note:
-
Declaring something as
-
An object may be fit for use in constant expressions without being declared
This is possible because
So when do I actually have to use
[This is due to §5.19/2: A constant expression must not include a subexpression that involves "an lvalue-to-rvalue modification unless […] a glvalue of integral or enumeration type […]" Thanks to Richard Smith for correcting my earlier claim that this was true for all literal types.]
-
For a function to be fit for use in constant expressions, it must be explicitly declared
When can I / should I use both,
A. In object declarations. This is never necessary when both keywords refer to the same object to be declared.
is the same as
However, note that there may be situations when the keywords each refer to different parts of the declaration:
Here,
Both keywords can be used in the declaration of objects as well as functions. The basic difference when applied to objects is this:
-
const declares an object as constant. This implies a guarantee that once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization.-
constexpr declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr is not the only way to do this.When applied to functions the basic difference is this:
-
const can only be used for non-static member functions, not functions in general. It gives a guarantee that the member function does not modify any of the non-static data members (except for mutable data members, which can be modified anyway).-
constexpr can be used with both member and non-member functions, as well as constructors. It declares the function fit for use in constant expressions. The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly (†):- The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single
returnstatement is allowed. In the case of a constructor, only an initialization list, typedefs, and static assert are allowed. (= defaultand= deleteare allowed, too, though.)
- As of C++14, the rules are more relaxed, what is allowed since then inside a constexpr function:
asmdeclaration, agotostatement, a statement with a label other thancaseanddefault, try-block, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the definition of a variable for which no initialization is performed.
- The arguments and the return type must be literal types (i.e., generally speaking, very simple types, typically scalars or aggregates)
Constant expressions
As said above,
constexpr declares both objects as well as functions as fit for use in constant expressions. A constant expression is more than merely constant:-
It can be used in places that require compile-time evaluation, for example, template parameters and array-size specifiers:
template
class fixed_size_list
{ /*...*/ };
fixed_size_list mylist; // X must be an integer constant expression
int numbers[X]; // X must be an integer constant expression-
But note:
-
Declaring something as
constexpr does not necessarily guarantee that it will be evaluated at compile time. It can be used for such, but it can be used in other places that are evaluated at run-time, as well.-
An object may be fit for use in constant expressions without being declared
constexpr. Example:int main()
{
const int N = 3;
int numbers[N] = {1, 2, 3}; // N is constant expression
}This is possible because
N, being constant and initialized at declaration time with a literal, satisfies the criteria for a constant expression, even if it isn't declared constexpr.So when do I actually have to use
constexpr?- An object like
Nabove can be used as constant expression without being declaredconstexpr. This is true for all objects that are:
constand
- of integral or enumeration type and
- initialized at declaration time with an expression that is itself a constant expression.
[This is due to §5.19/2: A constant expression must not include a subexpression that involves "an lvalue-to-rvalue modification unless […] a glvalue of integral or enumeration type […]" Thanks to Richard Smith for correcting my earlier claim that this was true for all literal types.]
-
For a function to be fit for use in constant expressions, it must be explicitly declared
constexpr; it is not sufficient for it merely to satisfy the criteria for constant-expression functions. Example:template
class list
{ };
constexpr int sqr1(int arg)
{ return arg * arg; }
int sqr2(int arg)
{ return arg * arg; }
int main()
{
const int X = 2;
list mylist1; // OK: sqr1 is constexpr
list mylist2; // wrong: sqr2 is not constexpr
}When can I / should I use both,
const and constexpr together?A. In object declarations. This is never necessary when both keywords refer to the same object to be declared.
constexpr implies const.constexpr const int N = 5;is the same as
constexpr int N = 5;However, note that there may be situations when the keywords each refer to different parts of the declaration:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}Here,
NP is declared as an address constant-expression, i.e. a pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both constexpr and const arCode Snippets
template<int N>
class fixed_size_list
{ /*...*/ };
fixed_size_list<X> mylist; // X must be an integer constant expression
int numbers[X]; // X must be an integer constant expressionint main()
{
const int N = 3;
int numbers[N] = {1, 2, 3}; // N is constant expression
}template<int N>
class list
{ };
constexpr int sqr1(int arg)
{ return arg * arg; }
int sqr2(int arg)
{ return arg * arg; }
int main()
{
const int X = 2;
list<sqr1(X)> mylist1; // OK: sqr1 is constexpr
list<sqr2(X)> mylist2; // wrong: sqr2 is not constexpr
}constexpr const int N = 5;constexpr int N = 5;Context
Stack Overflow Q#14116003, score: 837
Revisions (0)
No revisions yet.