<!-- Start of markdown source --> 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 <stdio.h> #include <stdint.h> #include <inttypes.h> template<class T> struct magic_number { }; // Template specializations for int32_t and int64_t template<> struct magic_number<int32_t> { static constexpr int32_t value{10}; static constexpr const char *fmt{"%" PRId32}; }; template<> struct magic_number<int64_t> { static constexpr int64_t value{20}; static constexpr const char *fmt{"%" PRId64}; }; // Variable templates template <class T> constexpr T magic_number_v = magic_number<T>::value; template <class T> constexpr const char *magic_fmt_v = magic_number<T>::fmt; template <class T> void foo() { printf(magic_fmt_v<T>, magic_number_v<T>); } int main() { foo<int32_t>(); // Prints 10 printf("\n"); foo<int64_t>(); // 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 <array> 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<std::pair<color, int>, 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" ) <!-- End of markdown source --> <div id="footer"></div>