TOC will be added in the final post, since github doesn't recognize [TOC] option...
This file is published as bfilipek.com/C++17 features blog post.
##Intro
Work in Progress! I am happy to see your help with the list! :)
If you have code examples, better explanations or any ideas, let me know! I am happy to update the current post so that it has some real value for others.
The plan is to have a list of features with some basic explanation, little example (if possible) and some additional resources, plus a note about availability in compilers. Probably, most of the features might require separate articles or even whole chapters in books, so the list here will be only a jump start.
The list comes from the following resources:
- SO: What are the new features in C++17?
- cppreference.com/C++ compiler support.
- AnthonyCalandra/modern-cpp-features cheat sheet - unfortunately it doesn't include all the features of C++17, so this is also why I've started a separate try on that.
- plus other findings and mentions
##Language Features
###New auto rules for direct-list-initialization N3922
GCC: 5.0 | Clang: 3.8 | MSVC: 14.0 |
---|
Fixes some cases with auto type deduction. The full background can be found in Auto and braced-init-lists, by Ville Voutilainen.
It fixes the problem of deducing std::initialize_list
like:
auto x = foo(); // copy-initialization
auto x{foo}; // direct-initialization, initializes an initializer_list
int x = foo(); // copy-initialization
int x{foo}; // direct-initialization
And for the direct initialization, new rules are:
- 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.
Basically, auto x { 1 };
will be now deduced as int
, but before it was an initializer list.
###static_assert with no message N3928
GCC: 6.0 | Clang: 2.5 | MSVC: 15.0 preview 5 |
---|
Self-explanatory. It allows just to have the condition without passing the message, 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).
###typename in a template template parameter
GCC: 5.0 | Clang: 3.5 | MSVC: 14.0 |
---|
Allows you to use typename
instead of class
when declaring a template template parameter. Normal type parameters can use them interchangeably, but template template parameters were restricted to class
, so this change unifies these forms somewhat.
template <template <typename...> typename Container>
// used to be invalid ^^^^^^^^
struct foo;
foo<std::vector> my_foo;
###Removing trigraphs N4086
GCC: 5.1 | Clang: 3.5 | MSVC: not yet |
---|
Removes ??=
, ??(
, ??>
, ...
Makes the implementation a bit simpler, see MSDN Trigraphs
###Nested namespace definition N4230
GCC: 6.0 | Clang: 3.6 | MSVC: 14.3 |
---|
Allows to write:
namespace A::B::C {
//…
}
Rather than:
namespace A {
namespace B {
namespace C {
//…
}
}
}
###Attributes for namespaces and enumerators N4266
GCC: 4.9 (namespaces)/ 6 (enums) | Clang: 3.4 | MSVC: 14.0 |
---|
Permits attributes on enumerators and namespaces. More details in N4196.
enum E {
foobar = 0,
foobat [[deprecated]] = foobar
};
E e = foobat; // Emits warning
namespace [[deprecated]] old_stuff{
void legacy();
}
old_stuff::legacy(); // Emits warning
###u8 character literals N4267
GCC: 6.0 | Clang: 3.6 | MSVC: 14.0 |
---|
u8'U'
character literals.
update needed...
###Allow constant evaluation for all non-type template arguments N4268
GCC: 6.0 | Clang: 3.6 | MSVC: not yet |
---|
todo...
GCC: 6.0 | Clang: 3.6 | MSVC: not yet |
---|
More background here in P0036
Articles:
###Remove Deprecated Use of the register Keyword P0001R1
GCC: 7.0 | Clang: 3.8 | MSVC: not yet |
---|
The register
keyword was deprecated in the 2011 C++ standard. C++17 tries to clear the standard, so the keyword is now removed.
###Remove Deprecated operator++(bool) P0002R1
GCC: 7.0 | Clang: 3.8 | MSVC: not yet |
---|
The ++ operator for bool
was deprecated in the original 1998 C++ standard, and it is past time to remove it formally.
###Removing Deprecated Exception Specifications from C++17 P0003R5
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
Dynamic exception specifications were deprecated in C++11. This paper formally proposes removing the feature from C++17, while retaining the (still) deprecated throw()
specification strictly as an alias for noexcept(true)
.
###Make exception specifications part of the type system
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
Previously exception specifications for a function didn't belong to the type of the function, but it will be part of it.
We'll get an error in the case:
void (*p)() throw(int);
void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function
###Aggregate initialization of classes with base classes P0017R1
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
If a class was derived from some other type you couldn't use aggregate initialization. But now the restriction is removed.
struct base { int a1, a2; };
struct derived : base { int b1; };
derived d1{{1, 2}, 3}; // full explicit initialization
derived d1{{}, 1}; // the base is value initialized
To sum up: from the standard:
An aggregate is an array or a class with:
- no user-provided constructors (including those inherited from a base class),
- no private or protected non-static data members (Clause 11),
- no base classes (Clause 10) and // removed now!
- no virtual functions (10.3), and
- no virtual, private or protected base classes (10.1).
###Lambda capture of *this P0018R3
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
this
pointer is implicitly captured by lambdas inside member functions. Sometimes, it's useful to capture this
by value. Such change can reduce problems in multithreading.
###Using attribute namespaces without repetition P0028R4
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
todo...
###Dynamic memory allocation for over-aligned data P0035R4
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
todo...
###Unary fold expressions and empty parameter packs P0036R0
GCC: 6.0 | Clang: 3.9 | MSVC: not yet |
---|
todo...
###__has_include in preprocessor conditionals P0061R1
GCC: 5.0 | Clang: yes | MSVC: not yet |
---|
todo...
###Template argument deduction for class templates P0091R3
GCC: 7.0 | Clang: not yet | MSVC: not yet |
---|
todo...
###Non-type template parameters with auto type P0127R2
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
todo...
###Guaranteed copy elision P0135R1
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
Articles:
###New specification for inheriting constructors (DR1941 et al) P0136R1
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
todo...
###Direct-list-initialization of enumerations P0138R2
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
Allows to initialize enum class with a fixed underlying type:
enum class Handle : uint32_t { Invalid = 0 };
Handle h { 42 }; // OK
Allows to create 'strong types' that are easy to use...
###Stricter expression evaluation order P0145R3
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
todo...
###constexpr lambda expressions P0170R1
GCC: 7.0 | Clang: not yet | MSVC: not yet |
---|
todo...
###Differing begin and end types in range-based for P0184R0
GCC: 6.0 | Clang: 3.6 | MSVC: 15.0 Preview 5 |
---|
Changing the definition of range based for from:
{
auto && __range = for-range-initializer;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
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.
###[[fallthrough]] attribute
GCC: 7.0 | Clang: 3.9 | MSVC: 15.0 Preview 4 |
---|
Indicates that a fallthrough in a switch statement is intentional and a warning should not be issued for it. More details in P0068R0.
switch (c) {
case 'a':
f(); // Warning emitted, fallthrough is perhaps a programmer error
case 'b':
g();
[[fallthrough]]; // Warning suppressed, fallthrough is intentional
case 'c':
h();
}
###[[nodiscard]] attribute
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
[[nodiscard]]
is used to stress that the return value of a function is not to be discarded, on pain of a compiler warning. More details in P0068R0.
[[nodiscard]] int foo();
void bar() {
foo(); // Warning emitted, return value of a nodiscard function is discarded
}
This attribute can also be applied to types in order to mark all functions which return that type as [[nodiscard]]
:
[[nodiscard]] struct DoNotThrowMeAway{};
DoNotThrowMeAway i_promise();
void oops() {
i_promise(); // Warning emitted, return value of a nodiscard function is discarded
}
###[[maybe_unused]] attribute
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
Suppresses compiler warnings about unused entities when they are declared with [[maybe_unused]]
. More details in P0068R0.
static void impl1() { ... } // Compilers may warn about this
[[maybe_unused]] static void impl2() { ... } // Warning suppressed
void foo() {
int x = 42; // Compilers may warn about this
[[maybe_unused]] int y = 42; // Warning suppressed
}
###Ignore unknown attributes
GCC: Yes | Clang: 3.9 | MSVC: not yet |
---|
Clarifies that implementations should ignore any attribute namespaces which they do not support, as this used to be unspecified. More details in P0283R1.
//compilers which don't support MyCompilerSpecificNamespace will ignore this attribute
[[MyCompilerSpecificNamespace::do_special_thing]]
void foo();
###Pack expansions in using-declarations
GCC: not yet | Clang: 4.0 | MSVC: not yet |
---|
Allows you to inject names with using-declarations from all types in a parameter pack.
In order to expose operator()
from all base classes in a variadic template, we used to have to resort to recursion:
template <typename T, typename... Ts>
struct Overloader : T, Overloader<Ts...> {
using T::operator();
using Overloader<Ts...>::operator();
// […]
};
template <typename T> struct Overloader<T> : T {
using T::operator();
};
Now we can simply expand the parameter pack in the using-declaration:
template <typename... Ts>
struct Overloader : Ts... {
using Ts::operator()...;
// […]
};
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
Helps when using tuples as a return type. It will automatically create variables and tie
them. More details in P0144R0. Was originally called "structured bindings".
For example:
std::tie(a, b, c) = tuple; // a, b, c need to be declared first
Now we can write:
auto [ a, b, c ] = tuple;
Such expressions also work on structs, pairs, and arrays.
Articles:
- Steve Lorimer, C++17 Structured Bindings
- jrb-programming, Emulating C++17 Structured Bindings in C++14
- Simon Brand, Adding C++17 decomposition declaration support to your classes
###Hexadecimal floating-point literals
GCC: 3.0 | Clang: Yes | MSVC: not yet |
---|
Allows to express some special floating point values, for example, the smallest normal IEEE-754 single precision value is readily written as 0x1.0p-126
.
###init-statements for if and switch
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
New versions of the if and switch statements for C++: if (init; condition)
and switch (init; condition)
.
This should simplify the code. For example, previously you had to write:
{
auto val = GetValue();
if (val)
// on success
else
// on false...
}
Look, that val
has a separate scope, without it it will 'leak'.
Now you can write:
if (auto val = GetValue(); val)
// on success
else
// on false...
val
is visible only inside the if
and else
statements, so it doesn't 'leak'.
###Inline variables
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
Previously only methods/functions could be specified as inline
; now you can do the same with variables.
###DR: Matching of template template-arguments excludes compatible templates
GCC: 7.0 | Clang: 4.0 | MSVC: not yet |
---|
todo...
GCC: 6.0 | Clang: 3.7 | MSVC: 14.0 |
---|
More background in the original paper: PDF: N4152 and GOTW issue 47: Uncaught Exceptions.
The function returns the number of uncaught exception objects in the current thread.
###constexpr
if-statements
GCC: 7.0 | Clang: 3.9 | MSVC: not yet |
---|
The static-if for C++! This allows you to discard branches of an if statement at compile-time based on a constant expression condition.
if constexpr(cond)
statement1; // Discarded if cond is false
else
statement2; // Discarded if cond is true
This removes a lot of the necessity for tag dispatching and SFINAE:
template <typename T, std::enable_if_t<std::is_arithmetic<T>{}>* = nullptr>
auto get_value(T t) {/*...*/}
template <typename T, std::enable_if_t<!std::is_arithmetic<T>{}>* = nullptr>
auto get_value(T t) {/*...*/}
template <typename T>
auto get_value(T t, std::true_type) {/*...*/}
template <typename T>
auto get_value(T t, std::false_type) {/*...*/}
template <typename T>
auto get_value(T t) {
return get_value(t, std::is_arithmetic<T>{});
}
template <typename T>
auto get_value(T t) {
if constexpr (std::is_arithmetic_v<T>) {
//...
}
else {
//...
}
}
Articles:
- LoopPerfect Blog, C++17 vs C++14 - Round 1 - if-constexpr
- SO: constexpr if and static_assert
- Simon Brand: Simplifying templates and #ifdefs with if constexpr
##Library Features
###Merged: The Parallelism TS, a.k.a. “Parallel STL.”,
###Merged: The Library Fundamentals 1 TS (most parts)
###Merged: File System TS,
###Merged: The Mathematical Special Functions IS,
###Improving std::pair and std::tuple
###std::shared_mutex (untimed)