The new C++ Standard - C++17 - is near the end to be accepted and published. There’s already a working draft, and not that long ago it went to the final ISO balloting. It’s a good occasion to learn and understand what are the new features.

Let’s start slowly, and today we’ll look at language/library fixes and removed elements.

Intro & Series

This is the first post from my new series about C++17 details. I’ve already shared a lot of stuff, especially in my huge C++17 collaborative post from the beginning of the year. Still, it’s good to look at things in a bit more details.

The plan for the series

First of all, if you want to dig into the standard on your own, you can read the latest draft here:

N4659, 2017-03-21, Working Draft, Standard for Programming Language C++ - the link also appears on the isocpp.org.

Compiler support: C++ compiler support

In Visual Studio (since VS 2015 Update 3) you can try using Standard Version Switches and test your code conformance with the given standard: Standards version switches in the compiler.

Moreover, I’ve prepared a list of concise descriptions of all of the C++17 language features:

It’s a one-page reference card, PDF.

Removed things

The draft for the language contains now over 1586 pages! Due to compatibility requirements, the new features are added, but not much is removed. Fortunately, there are some things that could go away.

Removing trigraphs

Trigraphs are special character sequences that could be used when a system doesn’t support 7-bit ASCII - like in ISO 646 character set . For example ??= generated # , ??- produces ~ . BTW: All of C++’s basic source character set fits in 7-bit ASCII. The sequences are rarely used and by removing them the translation phase of the code might be simpler.

If you want to know more: c++03 - Purpose of Trigraph sequences in C++? - Stack Overflow, or Digraphs and trigraphs - Wikipedia.

More details in: N4086. If you really need trigraphs with Visual Studio, take a look at /Zc:trigraphs switch. Also, other compilers might leave the support in some way or the other. Other compiler status: done in GCC: 5.1 and Clang: 3.5.

Removing register keyword

The register keyword was deprecated in the 2011 C++ standard as it has no meaning. Now it’s being removed. This keyword is reserved and might be repurposed in the future revisions (for example auto keyword was reused and now is something powerful).

More details: P0001R1, MSVC 2017: not yet. Done in GCC: 7.0 and Clang: 3.8.

Remove Deprecated operator++(bool)

This operator is deprecated for a very long time! In C++98 is was decided that it’s better not to use it. But only in C++17, the committee agreed to remove it from the language.

More details: P0002R1, MSVC 2017: not yet. Done in GCC: 7.0 and Clang: 3.8.

Removing Deprecated Exception Specifications from C++17

In C++17 exception specification will be part of the type system (see P0012R1). Still the standard contains old and deprecated exception specification that appeared to be not practical and not used.

For example:

void fooThrowsInt ( int a ) throw ( int ) { printf_s ( "can throw ints

" ); if ( a == 0 ) throw 1 ; }

The above code is deprecated since C++11. The only practical exception declaration is throw() that mean - this code won’t throw anything. But since C++11 it’s advised to use noexcept .

For example in clang 4.0 you’ll get the following error:

error: ISO C++1z does not allow dynamic exception specifications [-Wdynamic-exception-spec] note: use 'noexcept(false)' instead

More details: P0003R5, MSVC 2017: not yet. Done in GCC: 7.0 and Clang: 4.0.

Removing auto_ptr

This is one of my favorite update to the language!

In C++11 we got smart pointers: unique_ptr , shared_ptr and weak_ptr . Thanks to the move semantics the language could finally support proper unique resource transfers. auto_ptr was old and buggy thing in the language - see the full reasons here - why is auto_ptr deprecated. It should be almost automatically converted to unique_ptr . For some time auto_ptr was deprecated (since C++11). Many compilers would report this like:

warning: 'template<class> class std::auto_ptr' is deprecated

Now it goes into a zombie state, and basically, your code won’t compile.

Here’s the error from: MSVC 2017 when using /std:c++latest :

error C2039: 'auto_ptr': is not a member of 'std'

If you need help with the conversion from auto_ptr to unique_ptr you can check Clang Tidy, as it provides auto conversion: Clang Tidy: modernize-replace-auto-ptr.

More details: N4190

In the linked paper N4190: there are also other library items that were removed: unary_function / binary_function , ptr_fun() , and mem_fun() / mem_fun_ref() , bind1st() / bind2nd() and random_shuffle .

Fixes

We can argue what is a fix in a language standard and what is not. Below I’ve picked three things that sound to me like a fix for something that was missed in the previous standards.

New auto rules for direct-list-initialization

Since C++11 we got a strange problem where:

auto x { 1 };

Is deduced as initializer_list . With the new standard, we can fix this, so it will deduce int (as most people would initially guess).

To make this happen, we need to understand two ways of initialization: copy and direct.

auto x = foo (); // copy-initialization auto x { foo }; // direct-initialization, initializes an // initializer_list (until C++17) int x = foo (); // copy-initialization int x { foo }; // direct-initialization

For the direct initialization, C++17 introduces new rules:

For a braced-init-list with only a single element, auto deduction will deduce from that entry; For a braced-init-list with more than one element, auto deduction will be ill-formed.

For example:

auto x1 = { 1 , 2 }; // decltype(x1) is std::initializer_list<int> auto x2 = { 1 , 2.0 }; // error: cannot deduce element type auto x3 { 1 , 2 }; // error: not a single element auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int> auto x5 { 3 }; // decltype(x5) is int

More details in N3922 and also in Auto and braced-init-lists, by Ville Voutilainen. Already working since MSVC 14.0, GCC: 5.0, Clang: 3.8.

static_assert with no message

Self-explanatory. It allows just to have the condition without passing the message, the version with the message will also be available. It will be compatible with other asserts like BOOST_STATIC_ASSERT (that didn’t take any message from the start).

static_assert ( std :: is_arithmetic_v < T >, "T must be arithmetic" ); static_assert ( std :: is_arithmetic_v < T >); // no message needed since C++17

More details: N3928, supported in MSVC 2017, GCC: 6.0 and Clang: 2.5.

Different begin and end types in range-based for

Since C++11 range-based for loop was defined internally as:

{ auto && __range = for - range - initializer ; for ( auto __begin = begin - expr , __end = end - expr ; __begin != __end ; ++ __begin ) { for - range - declaration = * __begin ; statement } }

As you can see, __begin and __end have the same type. That might cause some troubles - for example when you have something like a sentinel that is of a different type.

In C++17 it’s changed into:

{ auto && __range = for - range - initializer ; auto __begin = begin - expr ; auto __end = end - expr ; for ( ; __begin != __end ; ++ __begin ) { for - range - declaration = * __begin ; statement } }

Types of __begin and __end might be different; only the comparison operator is required. This little change allows Range TS users a better experience.

More details in P0184R0, supported in MSVC 2017, GCC: 6.0 and Clang: 3.6.

Summary

The language standard grows, but there’s some movement in the committee to remove and clean some of the features. For compatibility reasons, we cannot delete all of the problems, but one by one we can get some improvements.

Next time we’ll address language clarifications: like guaranteed copy elision or expression evaluation order. So stay tuned!

Once again, remember to grab my C++17 Language Ref Card .

And BTW: you can read about modern C++ (including C++17), in a recent book from Marius Bancila: Modern C++ Programming Cookbook