Looking at C++14

by Jens Weller

A few weeks ago the C++ committee meeting in Issaquah (WA;USA) ended, its most important result: the final draft for C++14, which has been published last week. As I have read through most papers of last and this year, a short overview which papers now have made it into the standard.

Not in C++14

Before I dive into the details of C++14, a short paragraph about what's not in C++14. First, neither modules or concepts were ever able to make it into the timeframe. For modules, not a lot of papers are actually showing progress here, so not much to say currently about it. I expect that concepts will keep evolving, and then become part of the next major C++ standard. That's also an important point: C++14 was never planned to be a full major version of C++, it is more or less an improvement for C++11. The second big trend in C++ standardization of 2013 was to group things into technical specifications, to already prepare for the standard after C++14. Some of those TS were very close to get into C++14, but didn't make it for various reasons: filesystem, dynamic runtime arrays (VLAs/std::dynarray) and std::optional are just 3 examples.

C++14

So, what are the new features of C++14? Already before the last meeting, clang had implemented all known C++14 features of the draft published after the Chicago meeting. Also this is a very good overview on the C++14 features implemented currently in clang. So these are the features currently implemented in clang:

N3323 - Tweak to certain C++ contextual conversions

This proposal tweaks certain contextual conversions in C++ to be correct. As the authors state:

The principal issue, in each of the four contexts cited in the Introduction, seems to lie in their common helpful but very strict requirement that limits a class to only one conversion operator while allowing for the conversion of a value of the class’s type to a corresponding value of a type specified by the context.

So, I think tweak is a very good word to say what this proposal does. No big change.

N3472 - binary literals

C++14 brings core language support for binary literals, which means you now can integrate binary literals as such in your code:

char c = 0b01011010

The binary literal has to start with 0b/0B.

N3638 - decltype(auto) && Return type deduction for normal function

This proposal makes decltype(auto) legal C++, plus the return type deduction for normal functions. The last is the actual issue which this paper deals with, decltype(auto) one of its results. The return type deduction occurs when a function has the return type auto and the compiler then finds the corresponding type in the return statement. This has issues like recursion or when returning different types from a function. Another problem in deduction is that auto never deduces to a reference, and auto&& always, this is one of the problems that decltype(auto) helps to solve:

Unfortunately, there is no way to get the effect of decltype with an auto return type; plain auto never deduces to a reference, and auto&& always deduces to a reference. This is a significant problem, as it means that forwarding functions can't use auto. We could consider using decltype semantics instead of the existing auto semantics, but that would mean giving different deduction semantics to auto depending on whether the declaration is of a variable or a function, and making auto functions different from lambdas.

Therefore, I propose to also allow decltype(auto) to get the decltype semantics without having to repeat the expression. For simplicity of specification and orthogonality I propose to allow it everywhere that plain auto is allowed, except for introducing a trailing-return-type. It occurs to me that the difference in meaning of decltype depending on the form of the expression (e.g. parenthesized or not) might be more surprising in this context, but I think it would be even more surprising if this worked differently from C++11 decltype.

N3648 - Initialized Lambda Captures

This is one of the updates to lambdas that C++14 brings, dealing with the capture part of a lambda:[](){}. This is the example from the proposal:

int x = 4;
auto y = [&r = x, x = x+1]()->int {
    r += 2;
    return x+2;
}(); // Updates ::x to 6, and initializes y to 7.

The capture creates its own variables within the internal lambda structure, so that r is a reference to ::x, and x is a copy of ::x. Variables in the capture list can either be captured or init-captured. One important improvement with this is also that in C++11 capturing by move is not supported for lambdas.

N3649 - Generic (Polymorphic) Lambda Expressions

This is one of the most important changes with C++14: to allow lambdas with auto as type specifier in the parameter declaration. In C++11 lambdas are implemented as a class with a non template call operator. When the parameters of a lambda function are of type auto, the anonymous class representing the lambda could contain a templated call operator() as implementation. So, lambdas in C++14 now allow auto type-specifier to indicate a generic lambda parameter:

auto add = [](auto a,auto b){return a + b;}

N3651 - variable templates

This is a little surprise, and something that could not be done before C++14: to declare a variable as a template. The paper uses pi as an example:

template<typename T>
constexpr T pi = T(3.1415926535897932385);

Other templates could now access this variable via pi<T>, or pi<double>. Currently the two known workarounds to this are:

  • constexpr static data members of template classes
  • constexpr function templates returning the const value

Both are workarounds, and can now be replaced with this proposal.

N3652 - relaxing requirements for constexpr functions

constexpr functions were introduced with C++11, but very restricted. This proposal has now added a lot more to the subset allowed to be done at compile time in constexpr functions. You can now in a constexpr function:

  • declare a variable that is not static or thread_local.
  • use if (else/if else) and switch (but no goto)
  • use loops (for(including ranged-for),do, do-while)
  • objects whose lifetime began within the constexpr evaluation can mutate (e.g. change)

N3653 - Member initializers and aggregates

I'm not sure if that is new, or just a wording fix as the proposal is rather short, but you can now use initialization braces on aggregate members such as arrays.

N3664 - clarifing memory allocation

This proposal aimed successfully at clarifying the wording for memory allocation in the C++ Standard.

N3760 - [[deprecated]]

C++14 adds an attribute for deprecated to the standard. Lets hope it gets used in upcoming standards. C++14 does only deprecate a few things (e.g. not std::rand, but std::random_shuffle).

3781 - Single quotation mark as digit separator

Most important feature ever. C++14 brings finally(!) the digit separator to C++. This has been a proposal discussed widely, as it is not that trivial to add a digit separator to an existing language, originally _ was favored, but this conflicted with UDLs from C++11. So, the committee settled for ' as the digit separator, which only separates digits as in 1'000'000'000. This can be also used in binary literals, also it makes it easier to compare numbers.

3778 - Sized deallocation in C++

C++11 introduced the option to define a static member function operator delete that has size as a parameter, indicating the size of the object to be deleted. C++11 did not introduce a global operator delete with size indication, which is now fixed in C++14.

Also not listed by clang as its only a small addition to the Standard library, an important feature of C++14 is make_unique, which basicly allows for writing C++ with out ever again using new or delete directly.

Issaquah - a last update to C++14

For now I only have listed the previously to Issaquah known features of C++14, a few more decisions took place in Issaquah. A good overview is the Trip Report from isocpp.org, the 5 most important tweaks to C++14 from Issaquah are:

N3887 - Consistent metafunction aliases

This paper deals with metafunction aliases, and that they should have a consistent naming. Analyzing the standard, the conclusion is that only tuple_element_t is missing from the standard. Which is added into C++14.

N3891 - renaming shared_mutex to shared_timed_mutex

The planned shared_mutex class is in essence a shared_timed_mutex, so that there is a naming conflict when a different implemented shared_mutex would be added to the standard. Hence the renaming, also that way the mutex is naming consistent with the other Standard C++ mutex types.

N3910 - What can signal handlers do?

This proposal did clarify the wording on signal handlers in the C++ standard.

N3924 - Discouraging rand in C++14

As previously mentioned, nothing has been deprecated in C++14. One of the candidates for deprecation is std::rand, which in this decision is already flagged for deprecation, but not deprecated. What is now deprecated is std::random_shuffle.

N3927 - definition of lock-free

Again tweaking the C++ Standard to be more precise, in this case for lock-free.

And after C++14?

I hope I listed all important features of C++14. What is the next big thing in C++ land after C++14 is hard to say. Everything that goes not into a technical specification has its fair chance to become part of the next C++ standard. It's been nearly one year, that I did read all papers for 3 meetings of the committee, so I will post a follow up to this post about what I think we will see next in C++ standardization. For the coming years I think that C++11 and C++14 adoption will be the most important part in C++ land. Any newer standard will play its role in the years of 202x.

 

Go back

Follow Meeting C++

tl_files/mcpp/yt.pngtl_files/mcpp/gplus-50.pngtl_files/mcpp/twitter.pngtl_files/mcpp/facebook.png