Last Update:
C++17 in details: fixes and deprecation
Table of Contents
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
- Fixes and deprecation (this post)
- Language clarification
- Templates
- Attributes
- Simplification
- Library changes - Filesystem
- Library changes - Parallel Algorithms
- Library changes - Utils
- Wrap up, Bonus - with a free ebook! :)
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 of the C++17 language features:
Download a free copy of my C++17 Cheat Sheet!
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](https://stackoverflow.com/questions/1234582/purpose-of-trigraph-sequences-in-c), 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.
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
I've prepared a valuable bonus for you!
Learn all major features of recent C++ Standards on my Reference Cards!
Check it out here: