Some cool features of C++ 14 and C++ 17

I am a Senior Software Engineer at Siemens Healthineers with a deep passion for C++ and crafting efficient, high-quality software solutions.
C++ 14
Variable Templates- C++14 allows defining a variable template, which is similar to a function template but defines a variable instead of a function. Variable templates can be used to define a family of variables with different types, but the same value or behaviour. For example:
#include <iostream> using namespace std; template<typename T> constexpr T pi = T(3.1415926535897932385); int main() { float x = pi<float>; int y = pi<int>; cout << "x = " << x << endl; cout << "y = " << y << endl; } OUTPUT- x = 3.14159 y = 3Return Type Deduction for Functions- C++14 allows deducing the return type of a function based on the type of its return statement. This can simplify the syntax of functions that return complex types, such as lambdas or templates. For example:
#include <iostream> using namespace std; // The return type is 'int' but it is auto deduced by compiler using auto keyword. auto divide(int x, double y) { if (y == 0) return static_cast<int>(0); else return x / static_cast<int>(y); } int main() { auto x = divide(10, 2.2); cout << "x = " << x; } OUTPUT- x = 5Aggregate Initialization- C++14 allows using brace initialization to initialize aggregate types, such as arrays, structures, and classes. This makes it easier and more consistent to initialize complex types. For example:
#include <iostream> using namespace std; struct Point { int x, y; }; int main() { // brace initialization Point p1 = { 1, 2 }; cout << p1.x << endl; cout << p1.y << endl; } OUTPUT- 1 2constexpr Functions- C++14 extends the use of
constexprfunctions, which are functions that can be evaluated at compile time allowing their result to be used in constant expressions, such as array sizes or template arguments. This can improve the performance and efficiency of the code by avoiding runtime calculations. For example:#include <iostream> using namespace std; constexpr int square(int x) { return x * x; } int main() { //calculating array size during compile time int a[square(5)]; a[24] = 80; cout << a[24] << endl; // evaluates at compile time constexpr int b = square(3); cout << b; } OUTPUT- 80 9Binary Literals & Digit separation- Binary literals provide a convenient way to represent a base-2 number. It is also possible to separate digits with
'.
For example:#include <iostream> using namespace std; int main() { // binary literal using '0b' int x = 0b110; // digit separation using ' for better readability int y = 0b1111'1111; cout << "x= " << x << " & " << "y= " << y; return 0; } OUTPUT- x= 6 & y= 255
C++ 17
Structured bindings- Structured bindings allow decomposing tuples, arrays, and other types into individual variables in a concise and readable way. For example:
#include <iostream> using namespace std; int main() { int arr[3] = { 1, 2, 3 }; // Here x,y,z are bound to the array elements using structured binding auto[x, y, z] = arr; cout << x << " " << y << " " << z << endl; return 0; } OUTPUT- 1 2 3if and switch with initializer-
ifandswitchstatements with initializer allow the use of an initializer, similar to theforloop, providing a more concise and readable syntax. For example:#include <iostream> using namespace std; auto get_value1() {return 5;} auto get_value2() {return -4;} int main() { if (auto value = get_value1(); value > 0) cout << "Value is positive: " << value << endl; switch (auto value = get_value2(); value) { case 0: std::cout << "Value is zero" << std::endl; break; default: std::cout << "Value is not zero: " << value << std::endl; break; } } OUTPUT- Value is positive: 5 Value is not zero: -4Nested namespaces- Nested namespaces can also be useful for organizing code into logical groups and improving code readability. By grouping related functions and variables inside a nested namespace, you can make it clearer which parts of the code are related to each other and what their purpose is. For example:
#include <iostream> namespace outer { namespace inner { void foo() { std::cout << "Hello from inner namespace!\n"; } } } int main() { outer::inner::foo(); // Hello from inner namespace! return 0; } OUTPUT- Hello from inner namespace!Direct list initialization of enums- This allows you to initialize an enumeration value directly from a list of values, rather than using a cast or an explicit constructor call. This feature can make your code more readable and can help to prevent errors caused by incorrect casting or constructor calls. For example:
#include <iostream> using namespace std; enum Color { RED, GREEN, BLUE }; int main() { Color c1{Color::RED}; // Direct list initialization Color c2 = Color::GREEN; // Copy initialization using an explicit constructor call cout << c1 << endl; cout << c2 << endl; return 0; } OUTPUT- 0 1constexpr if-
constexpr ifallows conditional compilation based on a compile-time condition, enabling more expressive and efficient code. The feature allows you to discard branches of an if statement at compile-time based on a constant expression condition. For example:#include <iostream> using namespace std; template <typename T> void print(T value) { if constexpr(is_pointer<T>()) { cout << "Pointer value: " << value << endl; } else { cout << "Non-pointer value: " << value << endl; } } int main() { int x = 5; int* p = &x; print(p); print(x); return 0; } OUTPUT- Pointer value: 0x7ffdf8c... Non-pointer value: 5
There are more new features in C++ 14 and C++ 17 versions, but these are the most used and important ones.
There is also a newer version which is C++ 20, which has several important and major additions to its features.



