Features
Upcoming Events

ISO C++ standards meeting

June 16-21, Sofia, Bulgaria

 

CppCon 2025

September 13-19, Aurora, CO, USA

 

C++ Day 2025

October 25, Pavia, Italy

 

Meeting C++ 2025

November 6-8, Berlin, Germany

 

ISO C++ standards meeting

November 3-8, Kona, HI, USA

Wiki Home  >   cpp14 language

cpp14 language

C++14 Language Extensions

The following are the main additions and improvements to the C++ standard language in C++14. There are also miscellaneous smaller improvements and bug fixes besides those listed here, including various “transparent” improvements of the “now guarantees the program does what you would expect in a corner case you didn’t notice yet” variety.

Binary literals

C++ now supports binary literals:

// the answer to life, the universe, etc. in...auto a1 = 42;        // ... decimalauto a2 = 0x2A;      // ... hexadecimalauto a3 = 0b101010;  // ... binary

This works well in combination with the new'digit separators, for example to separate nybbles or bytes:

auto a = 0b100'0001;  // ASCII 'A'

See also:

Generalized return type deduction

C++11 permitted automatically deducing the return type of a lambda function whose body consisted of only a singlereturn statement:

// C++11[=]() -> some_type { return foo() * 42; } // ok[=]                { return foo() * 42; } // ok, deduces "-> some_type"

This has been expanded in two ways. First, it now works even with more complex function bodies containing more than onereturn statement, as long as all return statements return the same type:

// C++14[=] {                                     // ok, deduces "-> some_type"    while( something() ) {        if( expr ) {            return foo() * 42;            // with arbitrary control flow        }    }    return bar.baz(84);                   // & multiple returns}                                         //   (types must be the same)

Second, it now works with all functions, not just lambdas:

// C++11, explicitly named return typesome_type f()         { return foo() * 42; } // okauto f() -> some_type { return foo() * 42; } // ok// C++14auto f()              { return foo() * 42; } // ok, deduces "-> some_type"auto g() {                                // ok, deduces "-> some_type"    while( something() ) {        if( expr ) {            return foo() * 42;            // with arbitrary control flow        }    }    return bar.baz(84);                   // & multiple returns}                                         //   (types must be the same)

Of course, this requires the function body to be visible.

Finally, someone will ask: “Hmm, does this work for recursive functions?” The answer is yes, as long as areturn precedes the recursive call.

See also:

decltype(auto)

Given these functions:

string  lookup1();string& lookup2();

In C++11 we could write the following wrapper functions which remember to preserve the reference-ness of the return type:

string  look_up_a_string_1() { return lookup1(); }string& look_up_a_string_2() { return lookup2(); }

In C++14, we can automate that:

decltype(auto) look_up_a_string_1() { return lookup1(); }decltype(auto) look_up_a_string_2() { return lookup2(); }

Note:decltype(auto) is primarily useful for deducing the return type of forwarding functions and similar wrappers, as shown above, where you want the type to exactly “track” some expression you’re invoking. However,decltype(auto) is not intended to be a widely used feature beyond that. In particular, although it can be used to declare local variables, doing that is probably just an antipattern since a local variable’s reference-ness should not depend on the initialization expression. Also, it is sensitive to how you write the return statement. These two functions have different return types:

decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; }decltype(auto) look_up_a_string_2() { auto str = lookup1(); return(str); }

The first returnsstring, the second returnsstring &, which is a reference to the local variablestr.

See also:

Generalized lambda captures

In C++11, lambdas could not (easily) capture by move. In C++14, we have generalized lambda capture that solves not only that problem, but allows you to define arbitrary new local variables in the lambda object. For example:

auto u = make_unique<some_type>( some, parameters );  // a unique_ptr is move-onlygo.run( [ u=move(u) ] { do_something_with( u ); } ); // move the unique_ptr into the lambda

In the above example, we kept the name of the variableu the same inside the lambda. But we’re not limited to that… we can rename variables:

go.run( [ u2=move(u) ] { do_something_with( u2 ); } ); // capture as "u2"

And we can add arbitrary new state to the lambda object, because each capture creates a new type-deduced local variable inside the lambda:

int x = 4;int z = [&r = x, y = x+1] {            r += 2;         // set x to 6; "R is for Renamed Ref"            return y+2;     // return 7 to initialize z        }(); // invoke lambda

See also:

Generic lambdas

Lambda function parameters can now beauto to let the compiler deduce the type. This generates a lambda type with a templatedoperator() so that the same lambda object can be invoked with any suitable type and a type-safe function with the right parameter type will be automatically generated.

In C++11, we had to explicitly state the type of a lambda parameter, which was often fine but sometimes annoying:

// C++11: have to state the parameter typefor_each( begin(v), end(v), [](decltype(*cbegin(v)) x) { cout << x; } );sort( begin(w), end(w), [](const shared_ptr<some_type>& a,                            const shared_ptr<some_type>& b) { return *a<*b; } );auto size = [](const unordered_map<wstring, vector<string>>& m) { return m.size(); };

In C++14, we can get type deduction for the same functions we could write in C++11:

// C++14: just deduce the typefor_each( begin(v), end(v), [](const auto& x) { cout << x; } );sort( begin(w), end(w), [](const auto& a, const auto& b) { return *a<*b; } );

On top of that, we can now express something new we couldn’t express before, namely a lambda that will work with any suitable type and just do the right thing:

// C++14: new expressive powerauto size = [](const auto& m) { return m.size(); };

Note that this new version ofsize is not limited tounordered_map<wstring, vector<string>>s, but can be invoked with any type that has a.size() member function. Furthermore, because it also implicitly deduces the return type, the return type will be whateverm.size() returns, which can be different for different types.

See also:

Variable templates

In C++11, the addition ofusing type aliases andconstexpr functions largely replaced the need for “traits” templates. If you want to compute a type then prefer using a templated type aliasalias_t<T> instead of atraits<T>::type, and if you want to compute a value then prefer using avalue_v(); function that isconstexpr instead of atraits<T>::value.

So far, so good. But it turns out that sometimes we end up creatingconstexpr functions only to return a constant, and since we can templatize the function we can return the constant “cast” to the correct type. But the function only exists because we can’t express a templated variable directly.

Enter the variable template:

// math constant with precision dictated by actual typetemplate<typename T> constexpr T pi = T(3.14159265358979323846);// Example use:template<class T> T area_of_circle_with_radius(T r) { return pi<T> * r * r; }// Same use, in a  more C++14-stylish way:auto area_of_circle_with_radius = [](auto r) { return pi<decltype(r)> * r * r; };

See also:

Extendedconstexpr

In C++11, to make a functionconstexpr can mean rewriting it. For example, let’s say we have thisconstexpr function:

constexpr int my_charcmp( char c1, char c2 ) {    return (c1 == c2) ? 0 : (c1 < c2) ? : -1 : 1;}

That’s fine and useful for characters, so why not extend it to strings? That would require iteration over the characters of the string, which C++11 did not allow inconstexpr functions, so the C++11 version that supports strings would have to be recursive instead (and a little more complicated).

C++14 now allows more things inside the body ofconstexpr functions, notably:

  • local variable declarations (notstatic orthread_local, and no uninitialized variables)
  • mutating objects whose lifetime began with the constant expression evaluation
  • if,switch,for,while,do-while (notgoto)

So in C++14, the above function generalized to strings can stay idiomatic, and use a normal loop directly:

constexpr int my_strcmp( const char* str1, const char* str2 ) {    int i = 0;    for( ; str1[i] && str2[i] && str1[i] == str2[i]; ++i )        { }    if( str1[i] == str2[i] ) return 0;    if( str1[i] < str2[i] ) return -1;    return 1;}

C++14 also removes the C++11 rule thatconstexpr member functions are implicitlyconst.

See also:

The[[deprecated]] attribute

Thedeprecated attribute allows marking an entity deprecated, which makes it still legal to use but puts users on notice that use is discouraged and may cause a warning message to be printed during compilation.

The attribute may be applied to the declaration of a class, atypedef-name, a variable, a non-static data member, a function, an enumeration, or a template specialization.

See also:

Digit separators

The single-quote character' can now be used anywhere within a numeric literal for aesthetic readability. It does not affect the numeric value.

auto million = 1'000'000;auto pi = 3.14159'26535'89793;

See also:

PleaseLogin to submit a recommendation.

If you don’t have an account, you canregister for free.