C++14 support has been shipped as part of the ARM and MSP430 18.1.1.LTS; and
C6000 8.3.0 release. This article serves to introduce various new features in
the language, as well as to provide small examples of how they might apply to
embedded application development.
## The **constexpr** type specifier
The **constexpr** specifier was introduced in C++11. While similar in purpose to
the **const** qualifier, the guarantee provided by **constexpr** is much stronger.
While **const** provides a guarantee that an object shall not be modified from its
original value, **constexpr** asserts that the associated entity can be evaluated
at compile time, resulting in a truly constant value.
**constexpr** may be applied to both variables and functions.
### Variables and Data Members
**constexpr** variables are helpful as type-safe replacements for macros, and
can be used to provide descriptive names for what would otherwise be a 'magic'
number or value, without relying upon the compiler to optimize away the
variable itself.
```cpp
constexpr double PI = 3.1415926535;
double circumference(double radius) { return PI * (2 * radius); }
```
**constexpr** variables can be used in place of macros for things like memory-mapped
registers, ensuring that:
* The address has an actual name, rather than being the result of token replacement
* The address has an associated type, which could potentially disambiguate various
fields and operations
```cpp
struct mmr {
unsigned int a:1;
unsigned int b:12;
unsigned int c:10;
unsigned int d:9;
};
constexpr volatile struct mmr *MMR = (volatile struct mmr *)(0x1234abcd);
/* Now code can say 'MMR->a' rather than relying on a function-like macro to
access the first bit */
```
A more advanced usage for **constexpr** variables is to declare static data
members in a class type. This ties the compile-time value to the type. This is
useful when utilizing a generic algorithm with different types, when a constant
is the only thing that changes.
```cpp
#include
#include
#include
template struct magic_number { };
// Template specializations for int32_t and int64_t
template<>
struct magic_number {
static constexpr int32_t value{10};
static constexpr const char *fmt{"%" PRId32};
};
template<>
struct magic_number {
static constexpr int64_t value{20};
static constexpr const char *fmt{"%" PRId64};
};
// Variable templates
template
constexpr T magic_number_v = magic_number::value;
template
constexpr const char *magic_fmt_v = magic_number::fmt;
template
void foo() { printf(magic_fmt_v, magic_number_v); }
int main() {
foo(); // Prints 10
printf("\n");
foo(); // Prints 20
printf("\n");
}
```
In an embedded application, this type of generic programming can help separate
configurations and values for various boards or subtargets. Instead of int32_t
and int64_t specializations of magic_number, the application can instead use
enumeration values for each particular subtarget, which is chosen at compile time.
### Functions
**constexpr** functions provide a way to implement compile-time constants that
require some amount of algorithmic analysis to generate. A call to a **constexpr**
function is interpreted by the compiler during compilation, and its return value
value replaces the call in the code.
```cpp
/* More powerful than macros because these are now type-safe, can be
overloaded, and may also be templates. */
constexpr unsigned int low(unsigned int i) { return i & 0xffff; }
constexpr unsigned int high(unsigned int i) { return low(i >> 16); }
int max(int a, int b) { return ((a > b) ? a : b); }
```
```cpp
#include
enum color {
red,
blue,
orange,
green,
};
/* This array is a compile-time constant. As long as its address is not
taken, it will not generate any code by itself. */
constexpr std::array, 4> pair_array{
{ {red, 0x255}, {blue, 0x10}, {orange, 0x1000}, {green, 0x0}, }
};
constexpr int get_color_val(color c)
{
/* constexpr functions may contain loops */
for (int i = 0; i < pair_array.size(); i++)
if (pair_array[i].first == c) return pair_array[i].second;
return -1;
}
int main()
{
/* Go search for all the colors and extract their associated int values
as constant expressions. */
constexpr int color_vals[pair_array.size()] = {
get_color_val(red), get_color_val(blue),
get_color_val(orange), get_color_val(green),
};
/* Validate the values */
static_assert(color_vals[0] == 0x255, "Value 0 is incorrect");
static_assert(color_vals[1] == 0x10, "Value 1 is incorrect");
static_assert(color_vals[2] == 0x1000, "Value 2 is incorrect");
static_assert(color_vals[3] == 0x0, "Value 3 is incorrect");
}
```
### More Information
[The CPPReference Page for **constexpr**]( https://en.cppreference.com/w/cpp/language/constexpr "constexpr at cppreference.com" )