Final features of C++17

published at 30.06.2016 14:32 by Jens Weller

With last weeks C++ committee meeting in Oulu, C++17 is feature complete and on its way to become an international standard. After the last meeting in Jacksonville I had little hope to see big surprises, but Oulu managed to add a few important and interesting features to the new standard. There is a very good overview on Reddit and the recent CppCast with Herb Sutter (plus his trip report) also gives good insights. Also a more complete overview of C++17 is available as a presentation from Michael Wong.

First things first

As I said, a lot of things were already very clear after the meeting in Jacksonville. I wrote a 3 part blog series about the proposals which will or won't go into C++17. We are entering a new era of C++, in which standards are released together with powerful technical specifications, which are on the way to be part of the next standard often. Which means, that the non C++17 features (think Concepts or Modules e.g.) will be available as addons in upcoming compiler releases. Visual Studio currently offers modules, while GCC is the first compiler with concept support. Clang also supports modules, and its likely that both Visual Studio and Clang will soon have an implementation based on the specification of the module TS.

Also, have in mind, that the next two meetings mostly will process reviews, feedback and issues flagged by national bodies (aka ISO member delegations). This will not add new things to the standard, but can have minor or major changes. But lets hope that all of the features go through the final reviews.

Final highlights of C++17

std::variant

Lets start with the most surprising to me: variant. Yes, seriously, C++17 brings std::variant. This is cool, and paves the way for future features building upon variant and other related ideas. Such as pattern matching, there was a very good talk on this at C++Now from David Sankel. std::variant is designed with the experience of boost::variant and other variant libraries. It has a very similar API to boost::variant:

variant<int, float> v, w;
v = 12;
int i = get<int>(v);
w = get<int>(v);
w = get<0>(v); // same effect as the previous line
w = v; // same effect as the previous line

get<double>(v); // ill formed
get<3>(v); // ill formed

try {
  get<float>(w); // will throw.
}
catch (bad_variant_access&) {}

Its nice to see that this feature passes into the C++17 standard, instead of taking a TS detour.

if constexpr(expression)

This is the C++ version of static if (more or less). It was for me one of the highlights in Jacksonville, that didn't make it back then. As expected, it did pass the final review in Oulu into C++17. With that, C++ is now able to easily have certain blocks only compiled, if a constexpr is evaluated to true during compile time:

if constexpr (std::is_integer ...) { //integerstuff }
else if constexpr (std::is_floating_point ...) { //floatingpointstuff }
else { // NaN ;) }

The proposal explicitly states, that the constexpr must be true to be included during compilation, but this has no effect on static_assert. A static_assert in a block which is not selected, still will trigger. This is seen as illformed by the standard.

Also interesting: the feature is written if constexpr, but the standard wording still names it constexpr if, but defines it as if constexpr.

auto in templates

With C++14, lambdas gained the ability to have generic parameters with auto. This is now also allowed for (non type) template parameters. This makes it easier to write template code, as auto is shorter then class or typename. This is also allowed for variadic templates, e.g. template<auto... a>.

structured bindings

Until now, there was a known trick to abuse std::tie to assign a tuple or pair to different variables directly, instead of having to deal with the result type manually. This was a hack, and also the variables had to exist, now you can declare the variables and initialize them in one line:

auto [a , b , c] = getvalues();

The braces are needed, getvalues returns a tuple. std::pair is not mentioned in the proposal, so its unclear if this works with pair, which is returned by the STL in some insert methods.

If and switch with initializer

Its possible now to declare variables in an if statement: if(int x = 42; true != false), this can be combined with the previous proposal. In an if statement the declared variables are also valid in the else part of the if statement. I remember that already Modern C++ Design showed a trick how to achieve this with braces, but only for a single variable.

This can have interesting use cases, such as locking only in an if or switch, also all functions returning status codes now can be handled inside the scope of the if. Essentially, this is equivalent to writing { var x = value; if(...){}else{}}.

Even more

This is not all, there is for example an improvement for copy ellision, the namespace std[0-9]+ is reserved for future standards. The overview on reddit also features lots of interesting discussions and comments.

C++17 evolves the standard further, the tools for standardization have matured and are working. Probably the biggest gain for C++. Those who would like to add certain features to the next C++ Standard (aka C++NEXT/C++20), should now start to make their plans. Standardization is driven by volunteer work, there is no paid committee, most committee members have C++ related day jobs. There is a good and detailed overview page at isocpp.org and there are various mailing lists and working groups to participate in.