An overview of C++14 language features

 

In this post, I’m going to highlight some of the new language features in the draft of the C++14 standard. This is an excerpt from my book C++11 Rocks: VS2013 Edition. I looked at the level of C++14 support in different compilers in a previous post.

Return type deduction for functions

The compiler will be able to deduce the return type of functions:

auto square(int n) 
{
    return n * n;
}

To get the compiler to figure out the return type, you start the declaration with auto but don’t specify a trailing return type. This is basically extending the return type deduction VS2013 does for lambdas to regular functions.

Generic lambdas

When specifying lambda parameters, you’ll be able to use auto instead of a type:

auto lambda = [](auto a, auto b) { return a * b; };

In C++ pseudocode, this definition is equivalent to the following:

struct lambda1
{
    template<typename A, typename B>
    auto operator()(A a, B b) const -> decltype(a * b)
    {
        return a * b;
    }
};
 
auto lambda = lambda1();

So using auto for parameters effectively makes the function call operator templated. The types of the parameters will be determined using the rules for template argument deduction rather than the type inference that happens with regular auto variables.

Extended capturing in lambdas

Another change to lambdas involves capturing variables. In C++14, captured variables can have an initializing expression:

auto timer = [val = system_clock::now()] { return system_clock::now() - val; };
// ... do stuff ...
timer();   // returns time since timer creation

In this example, val is assigned the current time which is then returned by the lambda expression. val doesn’t need to be an existing variable, so this is in effect a mechanism for adding data members to the lambda. The types of these members are inferred by the compiler.

This allows capturing move-only variables which isn’t possible in C++11:

auto p = make_unique<int>(10);
auto lmb = [p = move(p)] { return *p; }

It is equivalent to capturing a variable via move, although what’s happening under the hood is a bit more tricky. In reality, the capture block declares a new data member in the lambda called p. This member is initialized with p from outside the lambda which is cast to an rvalue reference.

Revised restrictions on constexpr functions

The proposal lists the following things which are going to be allowed in constexpr functions:

  • declarations in constexpr functions with the exception of static, thread_local or uninitialized variables
  • if and switch statements
  • looping constructs, including range-based for
  • modification of objects whose lifetime began within the constant expression evaluation.

This should make constexpr functions a lot more versatile.

constexpr variable templates

In addition to type and function templates, C++14 will allow constexpr variables to be templated. Here is how it will work:

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

There is no new syntax, the already existing template syntax is simply applied to a variable
here. This variable can then be used in generic functions:

template<typename T>
T area_of_circle_with_radius(T r) 
{
    return pi<T> * r * r;
}

The idea is that despite having a single initializing expression, it’s sometimes useful to vary the type of a variable used in a generic function.

More changes

There are more language changes on the way. They include:

  • Another alternative for type inference which will allow you to use decltype inference rules for auto variables.
  • Aggregate initialization will work for classes with in-class member initializers.
  • Built-in binary literals prefixed with 0b.
  • It’ll be possible to separate digits in a numeric literal with a single quote.
  • Another standard attribute called [[deprecated]] will be added with the purpose of marking deprecated parts of the code.

The standard is expected to be finalized some time this year. The good thing is that the work on adding new features into compilers is already well under way, and some of the features I described in this post can already be used.

 

Keen on mastering C++11/14? I’ve written a book about the C++11/14 features. You can get a VS2013, Clang or a GCC edition.

 

9 Responses to “An overview of C++14 language features”

  1. Saying only some of the features can be used is an understatement. To my knowledge, Clang has all of them working already, as well as libc++ being done with the library updates.

     
    • Chris
    • Yes, Clang has full support. However, not everybody uses Clang, and a lot of people need to write cross-platform code. Also, the standard hasn’t even been finalised. So I wouldn’t rush into using C++14 in production code just yet.

       
      • Alex Korban
  2. I think that the runtime size for array’s (a.k.a VLA’s) was removed from the draft(s) and put into a TS (Technical Specification).

     
    • garfen
    • You’re right, thanks. I’ve updated the post.

       
      • Alex Korban
  3. It seems, example of the extended capturing would look better like following:

    // at 12 am:
    auto now = [val = system_clock::now()] { return val; };
    now(); // returns 12 am
    sleep_for(std::chrono::hours(1));
    now(); // returns 12 am still again

     
    • letika
    • Yes, that would be better. I’ve updated the example to

      auto timer = [val = system_clock::now()] { return system_clock::now() – val; };

      which I think is even nicer (somebody suggested this on Reddit).

       
      • Alex Korban
  4. I have a question and a correction.

    From generic lambda section:

    “The types of the parameters will be determined using the rules for template argument deduction rather than the type inference that happens with regular auto variables.”

    I believe regular auto variables use template argument deduction rules as well. Are the type deduction rules used for generic lambda parameters and regular auto variables different?

    The constexpr variable template:

    template
    constexpr auto T pi = T(3.1415926535897932385);

    The type specifier should be ‘auto’ or ‘T’ but not both.

     
    • Michael Park
    • There is a difference, and that is handling of initializer lists. When an auto variable is given an initializer list, the type is inferred to be initializer_list. If you pass an initializer list to a templated function, you’ll get a compilation error.

      Thanks for spotting the typo, I corrected it.

       
      • Alex Korban
      • Yep, I remembered the corner case and came back to correct myself but you beat me to it. Thanks for confirming it anyway :)

         
        • Michael Park