Skip to content

Commit 5f7e449

Browse files
author
mikeblome
committed
more updates for relaxed constexpr, plus linting
1 parent 4677b8f commit 5f7e449

File tree

3 files changed

+653
-598
lines changed

3 files changed

+653
-598
lines changed

docs/cpp/constexpr-cpp.md

Lines changed: 149 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -17,178 +17,170 @@ manager: "ghogen"
1717
ms.workload: ["cplusplus"]
1818
---
1919
# constexpr (C++)
20-
The keyword `constexpr` was introduced in C++11 and improved in C++14. It means *constant expression*. Like `const`, it can be applied to variables so that a compiler error will be raised if any code attempts to modify the value. Unlike `const`, `constexpr` can also be applied to functions and class constructors. `constexpr` indicates that the value, or return value, is constant and, if possible, will be 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. And when a value can be computed at compile time instead of run time, it can help your program run faster and use less memory.
21-
22-
## Syntax
23-
24-
```
20+
21+
The keyword **constexpr** was introduced in C++11 and improved in C++14. It means *constant expression*. Like **const**, it can be applied to variables so that a compiler error will be raised if any code attempts to modify the value. Unlike **const**, **constexpr** can also be applied to functions and class constructors. **constexpr** indicates that the value, or return value, is constant and, if possible, will be computed at compile time.
22+
23+
A **constexpr** integral value can be used wherever a const integer is required, such as in template arguments and array declarations. And when a value can be computed at compile time instead of run time, it can help your program run faster and use less memory.
24+
25+
To limit the complexity of computing compile time constants, and their potential impacts of compilation time, the C++14 standard requires that the types involved in constant expressions be restricted to [literal types](trivial-standard-layout-and-pod-types.md#literal_types).
26+
27+
## Syntax
28+
29+
```
2530
constexpr literal-type identifier = constant-expression;
2631
constexpr literal-type identifier { constant-expression };
2732
constexpr literal-type identifier(params );
28-
constexpr ctor (params);
29-
```
30-
31-
#### Parameters
32-
`params`
33-
One or more parameters which must be a literal type (as listed below) and must itself be a constant expression.
34-
35-
## Return Value
36-
A constexpr variable or function must return one of the literal types, as listed below.
37-
38-
## Literal types
39-
To limit the complexity of computing compile time constants, and their potential impacts of compilation time, the C++14 standard requires that the types involved in constant expressions be restricted to literal types. A literal type is one whose layout can be determined at compile time. The following are the literal types:
40-
41-
1. void
42-
43-
2. scalar types
44-
45-
3. references
46-
47-
4. Arrays of void, scalar types or references
48-
49-
5. A class that has a trivial destructor, and one or more constexpr constructors that are not move or copy constructors. Additionally, all its non-static data members and base classes must be literal types and not volatile.
50-
51-
## constexpr variables
52-
The primary difference between const and constexpr variables is that the initialization of a const variable can be deferred until run time whereas a constexpr variable must be initialized at compile time. All constexpr variables are const.
53-
54-
- A variable can be declared with `constexpr`, if it has a literal type and is initialized. If the initialization is performed by a constructor, the constructor must be declared as `constexpr`.
55-
56-
- A reference may be declared as constexpr if the object that it references has been initialized by a constant expression and any implicit conversions that are invoked during initialization are also constant expressions.
57-
58-
- All declarations of a `constexpr` variable or function must have the `constexpr` specifier.
59-
60-
61-
62-
63-
64-
```cpp
65-
constexpr float x = 42.0;
66-
constexpr float y{108};
67-
constexpr float z = exp(5, 3);
68-
constexpr int i; // Error! Not initialized
69-
int j = 0;
70-
constexpr int k = j + 1; //Error! j not a constant expression
71-
```
72-
73-
## constexpr functions
74-
A `constexpr` function is one whose return value can be computed at compile when consuming code requires it. When its arguments are `constexpr` values, and consuming code requires the return value at compile time, for example to initialize a `constexpr` variable or provide a non-type template argument, it produces a compile-time constant. When called with non-`constexpr` arguments, or when its value is not required at compile-time, it produces a value at run time like a regular function. (This dual behavior saves you from having to write `constexpr` and non-`constexpr` versions of the same function.)
75-
76-
A `constexpr` function or constructor is implicitly `inline`.
77-
78-
The following rules apply to constexpr functions:
33+
constexpr ctor (params);
34+
```
35+
36+
## Parameters
37+
38+
*params*
39+
One or more parameters which must be a literal type and must itself be a constant expression.
40+
41+
## Return Value
42+
43+
A constexpr variable or function must return a [literal type](trivial-standard-layout-and-pod-types.md#literal_types).
44+
45+
## constexpr variables
46+
47+
The primary difference between const and constexpr variables is that the initialization of a const variable can be deferred until run time whereas a constexpr variable must be initialized at compile time. All constexpr variables are const.
48+
49+
- A variable can be declared with **constexpr**, if it has a literal type and is initialized. If the initialization is performed by a constructor, the constructor must be declared as **constexpr**.
50+
51+
- A reference may be declared as constexpr if the object that it references has been initialized by a constant expression and any implicit conversions that are invoked during initialization are also constant expressions.
52+
53+
- All declarations of a **constexpr** variable or function must have the **constexpr** specifier.
54+
55+
```cpp
56+
constexpr float x = 42.0;
57+
constexpr float y{108};
58+
constexpr float z = exp(5, 3);
59+
constexpr int i; // Error! Not initialized
60+
int j = 0;
61+
constexpr int k = j + 1; //Error! j not a constant expression
62+
```
63+
64+
## constexpr functions
65+
66+
A **constexpr** function is one whose return value can be computed at compile when consuming code requires it. When its arguments are **constexpr** values, and consuming code requires the return value at compile time, for example to initialize a **constexpr** variable or provide a non-type template argument, it produces a compile-time constant. When called with non-`constexpr** arguments, or when its value is not required at compile-time, it produces a value at run time like a regular function. (This dual behavior saves you from having to write **constexpr** and non-`constexpr** versions of the same function.)
67+
68+
A **constexpr** function or constructor is implicitly **inline**.
69+
70+
The following rules apply to constexpr functions:
7971
80-
- A `constexpr` function must accept and return only literal types.
72+
- A **constexpr** function must accept and return only [literal types](trivial-standard-layout-and-pod-types.md#literal_types).
8173
82-
- A `constexpr` function can be recursive.
74+
- A **constexpr** function can be recursive.
8375
8476
- It cannot be [virtual](../cpp/virtual-cpp.md). A a constructor cannot be defined as constexpr if the enclosing class has any virtual base classes.
8577
86-
- The body can be defined as `= default` or `= delete`.
78+
- The body can be defined as **= default** or **= delete**.
8779
88-
- The body can contain no `goto` statements or try blocks.
80+
- The body can contain no **goto** statements or try blocks.
8981
90-
- An explicit specialization of a non-constexpr template can be declared as `constexpr`:
91-
92-
- An explicit specialization of a `constexpr` template does not have to also be `constexpr`:
82+
- An explicit specialization of a non-constexpr template can be declared as **constexpr`:
9383
84+
- An explicit specialization of a **constexpr** template does not have to also be **constexpr`:
9485
95-
<!--conformance note-->
96-
The following rules apply to constexpr functions in Visual Studio 2017 and later:
86+
The following rules apply to **constexpr** functions in Visual Studio 2017 and later:
9787
98-
- It may contain if and switch statements, and all looping statements including for, range-based for, while, and do-while
99-
88+
- It may contain **if** and **switch** statements, and all looping statements including **for**, range-based for, **while**, and **do-while**.
89+
10090
- It may contain local variable declarations, but the variable must be initialized, must be a literal type, and cannot be static or thread-local. The locally-declared variable is not required to be const and may mutate.
10191
10292
- A constexpr non-static member function is not required to be implicitly const.
10393
104-
105-
```cpp
106-
constexpr float exp(float x, int n)
107-
{
108-
return n == 0 ? 1 :
109-
n % 2 == 0 ? exp(x * x, n / 2) :
110-
exp(x * x, (n - 1) / 2) * x;
111-
};
112-
```
113-
94+
95+
```cpp
96+
constexpr float exp(float x, int n)
97+
{
98+
return n == 0 ? 1 :
99+
n % 2 == 0 ? exp(x * x, n / 2) :
100+
exp(x * x, (n - 1) / 2) * x;
101+
};
102+
```
103+
114104
> [!TIP]
115-
> Note: In the Visual Studio debugger, you can tell whether a `constexpr` function is being evaluated at compile time by putting a breakpoint inside it. If the breakpoint is hit, the function was called at run-time. If not, then the function was called at compile time.
116-
117-
118-
## Example
119-
The following example shows `constexpr` variables, functions and a user-defined type. Note that in the last statement in main(), the `constexpr` member function GetValue() is a run-time call because the value is not required to be known at compile time.
120-
121-
```
122-
#include <iostream>
123-
124-
using namespace std;
125-
126-
// Pass by value
127-
constexpr float exp(float x, int n)
128-
{
129-
return n == 0 ? 1 :
130-
n % 2 == 0 ? exp(x * x, n / 2) :
131-
exp(x * x, (n - 1) / 2) * x;
132-
};
133-
134-
// Pass by reference
135-
constexpr float exp2(const float& x, const int& n)
136-
{
137-
return n == 0 ? 1 :
138-
n % 2 == 0 ? exp2(x * x, n / 2) :
139-
exp2(x * x, (n - 1) / 2) * x;
140-
};
141-
142-
// Compile time computation of array length
143-
template<typename T, int N>
144-
constexpr int length(const T(&ary)[N])
145-
{
146-
return N;
147-
}
148-
149-
// Recursive constexpr function
150-
constexpr int fac(int n)
151-
{
152-
return n == 1 ? 1 : n*fac(n - 1);
153-
}
154-
155-
// User-defined type
156-
class Foo
157-
{
158-
public:
159-
constexpr explicit Foo(int i) : _i(i) {}
160-
constexpr int GetValue()
161-
{
162-
return _i;
163-
}
164-
private:
165-
int _i;
166-
};
167-
168-
int main()
169-
{
170-
//foo is const:
171-
constexpr Foo foo(5);
172-
// foo = Foo(6); //Error!
173-
174-
//Compile time:
175-
constexpr float x = exp(5, 3);
176-
constexpr float y { exp(2, 5) };
177-
constexpr int val = foo.GetValue();
178-
constexpr int f5 = fac(5);
179-
const int nums[] { 1, 2, 3, 4 };
180-
const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };
181-
182-
//Run time:
183-
cout << "The value of foo is " << foo.GetValue() << endl;
184-
185-
}
186-
187-
```
188-
189-
## Requirements
190-
Visual Studio 2015
191-
192-
## See Also
193-
[Declarations and Definitions](../cpp/declarations-and-definitions-cpp.md)
194-
[const](../cpp/const-cpp.md)
105+
> Note: In the Visual Studio debugger, when debugging a non-optimised Debug build, you can tell whether a **constexpr** function is being evaluated at compile time by putting a breakpoint inside it. If the breakpoint is hit, the function was called at run-time. If not, then the function was called at compile time.
106+
107+
## Example
108+
109+
The following example shows **constexpr** variables, functions and a user-defined type. Note that in the last statement in main(), the **constexpr** member function GetValue() is a run-time call because the value is not required to be known at compile time.
110+
111+
```cpp
112+
#include <iostream>
113+
114+
using namespace std;
115+
116+
// Pass by value
117+
constexpr float exp(float x, int n)
118+
{
119+
return n == 0 ? 1 :
120+
n % 2 == 0 ? exp(x * x, n / 2) :
121+
exp(x * x, (n - 1) / 2) * x;
122+
};
123+
124+
// Pass by reference
125+
constexpr float exp2(const float& x, const int& n)
126+
{
127+
return n == 0 ? 1 :
128+
n % 2 == 0 ? exp2(x * x, n / 2) :
129+
exp2(x * x, (n - 1) / 2) * x;
130+
};
131+
132+
// Compile time computation of array length
133+
template<typename T, int N>
134+
constexpr int length(const T(&ary)[N])
135+
{
136+
return N;
137+
}
138+
139+
// Recursive constexpr function
140+
constexpr int fac(int n)
141+
{
142+
return n == 1 ? 1 : n*fac(n - 1);
143+
}
144+
145+
// User-defined type
146+
class Foo
147+
{
148+
public:
149+
constexpr explicit Foo(int i) : _i(i) {}
150+
constexpr int GetValue()
151+
{
152+
return _i;
153+
}
154+
private:
155+
int _i;
156+
};
157+
158+
int main()
159+
{
160+
//foo is const:
161+
constexpr Foo foo(5);
162+
// foo = Foo(6); //Error!
163+
164+
//Compile time:
165+
constexpr float x = exp(5, 3);
166+
constexpr float y { exp(2, 5) };
167+
constexpr int val = foo.GetValue();
168+
constexpr int f5 = fac(5);
169+
const int nums[] { 1, 2, 3, 4 };
170+
const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };
171+
172+
//Run time:
173+
cout << "The value of foo is " << foo.GetValue() << endl;
174+
175+
}
176+
177+
```
178+
179+
## Requirements
180+
181+
Visual Studio 2015
182+
183+
## See Also
184+
185+
[Declarations and Definitions](../cpp/declarations-and-definitions-cpp.md)
186+
[const](../cpp/const-cpp.md)

0 commit comments

Comments
 (0)