Tag Archive for C++17

C++17: Inline Variables

Before C++17, if your class had any non-const static data members, you had to allocate memory for them. For example, suppose you have the following class definition:

class MyClass
    static int s_anInt;
    static std::string s_aString;

Then your source file should contain the following:

int MyClass::s_anInt = 42;
std::string MyClass::s_aString = "Hello World!";

This is annoying.
C++17 now supports inline variables which allow you to write the MyClass definition as follows:

class MyClass
    static inline int s_anInt = 42;
    static inline std::string s_aString = "Hello World!";

This feature makes it easier to write header only classes that contain non-const static data members.

At the time of this writing, Microsoft Visual C++ 2017 does not yet support inline variables.


C++17: Direct vs Copy List Initialization

C++11 introduced the uniform initialization syntax using braced initializer lists. You have direct list initialization which does not include an equal sign, for example:

int myInt{42};

and you have copy list initialization which uses the equal sign, for example:

int myInt = {42};

The auto type deduction rules have changes in C++17. With C++17, if you use copy list initialization, then an initializer_list<> is deduced, for example:

auto initList1 = {42};
auto initList2 = {42, 84, 126};

All values in the braced initializer list must be of the same type. The following does not compile:

auto initList2 = {42, 84.42};

When you use direct list initialization, then a value is deduced. For example, the following deduces an int:

auto anInt{42};

This also means that the following causes a compilation error because more than 1 initialization value is given:

auto ints{42, 84, 126};

This is the new C++17 behavior. With C++11/C++14, all of the above would deduce to an initializer_list<int>.

This changed behavior is included since Microsoft Visual C++ 2015.


C++17: Nested Namespaces

The second post in this series of C++17 features highlights a tiny but very useful new feature called nested namespaces.

Using multi-level namespaces in C++ has always been a pain. Suppose you are writing a game and you have a namespace called Core::Graphics::Rendering. Before C++17 you had to resort to something as follows

namespace Core {
    namespace Graphics {
        namespace Rendering {

            class PostProcessor


This leaves you with a very big indentation scheme. You could try to make it look a bit better as follows:

namespace Core { namespace Graphics { namespace Rendering {

    class PostProcessor


But this does not always plays nice with the auto formatting functionality of your IDE.

Say hello to C++17 nested namespaces. Now you can simply write the following:

namespace Core::Graphics::Rendering {

    class PostProcessor


Nested namespaces are supported in Microsoft Visual C++ 2015 since Update 3.


C++17: Structured Bindings

This is a first post in a series of short articles on new C++17 features. These articles will not contain all little details of the new features being presented, but they give you an idea about what new functionality has been added to C++17.

This first article discusses structured bindings. They allow you to declare multiple variables with a single statement that are initialized with values from a pair, tuple, array, or even a struct.

Let’s look at an example using a tuple. Suppose you have the following tuple consisting of a double, string, and integer (note the use of the user-defined std::string literal s):

auto myTuple = std::make_tuple(1.1, "Hello"s, 42);

Before C++17, if you wanted to decompose this tuple into three separate variables, you could use tie() as follows:

double theDouble;
std::string theString;
int theInt;
std::tie(theDouble, theString, theInt) = myTuple;

That’s 4 lines of code just to decompose the tuple.

C++17 structured bindings allow you to do this with a single line:

auto[theDouble, theString, theInt] = myTuple;

It also works for pairs, and this comes in handy for example when using insert() to insert values into a map. insert() returns a pair with as first element an iterator to the inserted element, and as second element a Boolean that is true if the element was inserted successfully. You can decompose that pair as follows:

std::map<int, int> myMap{ {1, 11}, { 2,22 }, { 3,33 }};
auto[it, success] = myMap.insert({ 4,44 });

If you want to use a range-based for loop to iterate over the elements, you could do it as follows:

for (const auto& element : myMap) {
    std::cout << element.first << ": " << element.second << std::endl;

The type of the element variable is a pair containing the key and the value of the elements in the map.

Again, you can use structured bindings to make this shorter and easier to understand:

for (const auto&[key, value] : myMap) {
    std::cout << key << ": " << value << std::endl;

Structured bindings are available in Microsoft Visual C++ 2017 since Update 3.


Milestone: VS 2015 Update 2’s Standard Library is C++11, C++14, and C++17-so-far Feature Complete

The C++ Standard Library in the Visual Studio 2015 Update 2 release is C++11, C++14, and C++17-so-far feature complete. This includes all features from C++17 that are currently in that standard proposal: SFINAE-friendly result_of, improvements to pair and tuple, shared_mutex, removal of deprecated iostreams aliases, variable templates for type traits (is_same_v, …), as_const(), logical operator type traits (conjunction, …), owner_less<>, variadic lock_guard, and additions to <chrono>: floor(), ceil(), round(), and abs().
More information, including a detailed list can be found here.