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.
Note: This post was originally posted at my blog: Bartek's coding blog: C++17 in details: fixes and deprecation as part of the series about C++17 details.
Documents & Links
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 C++17 language features: grab it here. It's a one-page reference card, PDF.
There's even more: at the beginning of the year I've published long, collaborative article about most of C++17 features, have a look here. If you want to update it, add more examples, just do a pull request on the repo.
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\n");
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.
On my blog, I'm publishing more articles about C++17 details, so go there and stay tuned for more :)
Once again, remember to grab my C++17 Language Ref Card.
Like this article?
If want to read more from me, visit my blog at bfilipek.com. I write weekly about native/c++ programming stories.