Lably
Skip to content

C++14

  • 14 min read
  • 3 chapters

Related on Lably

Through Recursion, Binary number and Java (programming language)

Because earlier C++ standard revisions were noticeably late, the name "C++1y" was sometimes used instead until its approval, similarly to how the C++11 standard used to be termed "C++0x" with the expectation of its release before 2010 (although in fact it slipped into 2010 and finally 2011).

New language features

These are the features added to the core language of C++14.

Function return type deduction

C++11 allowed lambda functions to deduce the return type based on the type of the expression given to the return statement. C++14 provides this ability to all functions. It also extends these facilities to lambda functions, allowing return type deduction for functions that are not of the form return expression;.

In order to induce return type deduction, the function must be declared with auto as the return type, but without the trailing return type specifier in C++11:

<span id="mwIA"></span><span class="k" id="mwIQ">auto</span><span class="w" id="mwIg"> </span><span class="n" id="mwIw">DeduceReturnType</span><span class="p" id="mwJA">();</span><span class="w" id="mwJQ"> </span><span class="c1" id="mwJg">// Return type to be determined.</span>

If multiple return expressions are used in the function's implementation, then they must all deduce the same type.

Functions that deduce their return types can be forward declared, but they cannot be used until they have been defined. Their definitions must be available to the translation unit that uses them.

Recursion can be used with a function of this type, but the recursive call must happen after at least one return statement in the definition of the function:

<span id="mwMQ"></span><span class="k" id="mwMg">auto</span><span class="w" id="mwMw"> </span><span class="n" id="mwNA">Correct</span><span class="p" id="mwNQ">(</span><span class="kt" id="mwNg">int</span><span class="w" id="mwNw"> </span><span class="n" id="mwOA">i</span><span class="p" id="mwOQ">)</span> <span class="p" id="mwOg">{</span> <span class="w" id="mwOw"> </span><span class="k" id="mwPA">if</span><span class="w" id="mwPQ"> </span><span class="p" id="mwPg">(</span><span class="n" id="mwPw">i</span><span class="w" id="mwQA"> </span><span class="o" id="mwQQ">==</span><span class="w" id="mwQg"> </span><span class="mi" id="mwQw">1</span><span class="p" id="mwRA">)</span> <span class="w" id="mwRQ"> </span><span class="k" id="mwRg">return</span><span class="w" id="mwRw"> </span><span class="n" id="mwSA">i</span><span class="p" id="mwSQ">;</span><span class="w" id="mwSg"> </span><span class="c1" id="mwSw">// return type deduced as int</span> <span class="w" id="mwTA"> </span><span class="k" id="mwTQ">return</span><span class="w" id="mwTg"> </span><span class="n" id="mwTw">Correct</span><span class="p" id="mwUA">(</span><span class="n" id="mwUQ">i</span><span class="mi" id="mwUg">-1</span><span class="p" id="mwUw">)</span><span class="o" id="mwVA">+</span><span class="n" id="mwVQ">i</span><span class="p" id="mwVg">;</span><span class="w" id="mwVw"> </span><span class="c1" id="mwWA">// ok to call it now</span> <span class="p" id="mwWQ">}</span> <span class="k" id="mwWg">auto</span><span class="w" id="mwWw"> </span><span class="n" id="mwXA">Wrong</span><span class="p" id="mwXQ">(</span><span class="kt" id="mwXg">int</span><span class="w" id="mwXw"> </span><span class="n" id="mwYA">i</span><span class="p" id="mwYQ">)</span> <span class="p" id="mwYg">{</span> <span class="w" id="mwYw"> </span><span class="k" id="mwZA">if</span><span class="w" id="mwZQ"> </span><span class="p" id="mwZg">(</span><span class="n" id="mwZw">i</span><span class="w" id="mwaA"> </span><span class="o" id="mwaQ">!=</span><span class="w" id="mwag"> </span><span class="mi" id="mwaw">1</span><span class="p" id="mwbA">)</span> <span class="w" id="mwbQ"> </span><span class="k" id="mwbg">return</span><span class="w" id="mwbw"> </span><span class="n" id="mwcA">Wrong</span><span class="p" id="mwcQ">(</span><span class="n" id="mwcg">i</span><span class="mi" id="mwcw">-1</span><span class="p" id="mwdA">)</span><span class="o" id="mwdQ">+</span><span class="n" id="mwdg">i</span><span class="p" id="mwdw">;</span><span class="w" id="mweA"> </span><span class="c1" id="mweQ">// Too soon to call this. No prior return statement.</span> <span class="w" id="mweg"> </span><span class="k" id="mwew">return</span><span class="w" id="mwfA"> </span><span class="n" id="mwfQ">i</span><span class="p" id="mwfg">;</span><span class="w" id="mwfw"> </span><span class="c1" id="mwgA">// return type deduced as int</span> <span class="p" id="mwgQ">}</span>

Alternate type deduction on declaration

In C++11, two methods of type deduction were added. auto was a way to create a variable of the appropriate type, based on a given expression. decltype was a way to compute the type of a given expression. However, decltype and auto deduce types in different ways. In particular, auto always deduces a non-reference type, as though by using std::decay, while auto&& always deduces a reference type. However, decltype can be prodded into deducing a reference or non-reference type, based on the value category of the expression and the nature of the expression it is deducing:

<span id="mwkg"></span><span class="kt" id="mwkw">int</span><span class="w" id="mwlA"> </span><span class="n" id="mwlQ">i</span><span class="p" id="mwlg">;</span> <span class="kt" id="mwlw">int</span><span class="o" id="mwmA">&&</span><span class="w" id="mwmQ"> </span><span class="nf" id="mwmg">f</span><span class="p" id="mwmw">();</span> <span class="k" id="mwnA">auto</span><span class="w" id="mwnQ"> </span><span class="n" id="mwng">x3a</span><span class="w" id="mwnw"> </span><span class="o" id="mwoA">=</span><span class="w" id="mwoQ"> </span><span class="n" id="mwog">i</span><span class="p" id="mwow">;</span><span class="w" id="mwpA"> </span><span class="c1" id="mwpQ">// decltype(x3a) is int</span> <span class="k" id="mwpg">decltype</span><span class="p" id="mwpw">(</span><span class="n" id="mwqA">i</span><span class="p" id="mwqQ">)</span><span class="w" id="mwqg"> </span><span class="n" id="mwqw">x3d</span><span class="w" id="mwrA"> </span><span class="o" id="mwrQ">=</span><span class="w" id="mwrg"> </span><span class="n" id="mwrw">i</span><span class="p" id="mwsA">;</span><span class="w" id="mwsQ"> </span><span class="c1" id="mwsg">// decltype(x3d) is int</span> <span class="k" id="mwsw">auto</span><span class="w" id="mwtA"> </span><span class="n" id="mwtQ">x4a</span><span class="w" id="mwtg"> </span><span class="o" id="mwtw">=</span><span class="w" id="mwuA"> </span><span class="p" id="mwuQ">(</span><span class="n" id="mwug">i</span><span class="p" id="mwuw">);</span><span class="w" id="mwvA"> </span><span class="c1" id="mwvQ">// decltype(x4a) is int</span> <span class="k" id="mwvg">decltype</span><span class="p" id="mwvw">((</span><span class="n" id="mwwA">i</span><span class="p" id="mwwQ">))</span><span class="w" id="mwwg"> </span><span class="n" id="mwww">x4d</span><span class="w" id="mwxA"> </span><span class="o" id="mwxQ">=</span><span class="w" id="mwxg"> </span><span class="p" id="mwxw">(</span><span class="n" id="mwyA">i</span><span class="p" id="mwyQ">);</span><span class="w" id="mwyg"> </span><span class="c1" id="mwyw">// decltype(x4d) is int&</span> <span class="k" id="mwzA">auto</span><span class="w" id="mwzQ"> </span><span class="n" id="mwzg">x5a</span><span class="w" id="mwzw"> </span><span class="o" id="mw0A">=</span><span class="w" id="mw0Q"> </span><span class="n" id="mw0g">f</span><span class="p" id="mw0w">();</span><span class="w" id="mw1A"> </span><span class="c1" id="mw1Q">// decltype(x5a) is int</span> <span class="k" id="mw1g">decltype</span><span class="p" id="mw1w">(</span><span class="n" id="mw2A">f</span><span class="p" id="mw2Q">())</span><span class="w" id="mw2g"> </span><span class="n" id="mw2w">x5d</span><span class="w" id="mw3A"> </span><span class="o" id="mw3Q">=</span><span class="w" id="mw3g"> </span><span class="n" id="mw3w">f</span><span class="p" id="mw4A">();</span><span class="w" id="mw4Q"> </span><span class="c1" id="mw4g">// decltype(x5d) is int&&</span>

C++14 adds the decltype(auto) syntax. This allows auto declarations to use the decltype rules on the given expression.

The decltype(auto) syntax can also be used with return type deduction, by using decltype(auto) syntax instead of auto for the function's return type deduction.

Relaxed constexpr restrictions

C++11 introduced the concept of a constexpr-declared function; a function which could be executed at compile time. Their return values could be consumed by operations that require constant expressions, such as an integer template argument. However, C++11 constexpr functions could only contain a single expression that is returned (as well as static_asserts and a small number of other declarations).

C++14 relaxes these restrictions. Constexpr-declared functions may now contain the following:

  • Any declarations except:
    • static or thread_local variables.
    • Variable declarations without initializers.
  • The conditional branching statements if and switch.
  • Any looping statement, including range-based for.
  • Expressions which change the value of an object if the lifetime of that object began within the constant expression function. This includes calls to any non-const constexpr-declared non-static member functions.

goto statements are forbidden in C++14 relaxed constexpr-declared functions.

Also, C++11 stated that all non-static member functions that were declared constexpr were also implicitly declared const, with respect to this. That has since been removed; non-static member functions may be non-const. However, per the restrictions above, a non-const constexpr member function can only modify a class member if that object's lifetime began within the constant expression evaluation.

Variable templates

In prior versions of C++, only functions, classes or type aliases could be templated. C++14 allows the creation of variables that are templated. An example given in the proposal is a variable pi that can be read to get the value of pi for various types (e.g., 3 when read as an integral type; the closest value possible with float, double or long double precision when read as float, double or long double, respectively; etc.).

The usual rules of templates apply to such declarations and definitions, including specialization.

<span id="mwASI"></span><span class="k" id="mwASM">template</span><span class="o" id="mwASQ"><</span><span class="k" id="mwASU">typename</span><span class="w" id="mwASY"> </span><span class="nc" id="mwASc">T</span><span class="o" id="mwASg">></span> <span class="k" id="mwASk">constexpr</span><span class="w" id="mwASo"> </span><span class="n" id="mwASs">T</span><span class="w" id="mwASw"> </span><span class="n" id="mwAS0">pi</span><span class="w" id="mwAS4"> </span><span class="o" id="mwAS8">=</span><span class="w" id="mwATA"> </span><span class="n" id="mwATE">T</span><span class="p" id="mwATI">(</span><span class="mf" id="mwATM">3.141592653589793238462643383</span><span class="p" id="mwATQ">);</span> <span class="c1" id="mwATU">// Usual specialization rules apply:</span> <span class="k" id="mwATY">template</span><span class="o" id="mwATc"><></span> <span class="k" id="mwATg">constexpr</span><span class="w" id="mwATk"> </span><span class="k" id="mwATo">const</span><span class="w" id="mwATs"> </span><span class="kt" id="mwATw">char</span><span class="o" id="mwAT0">*</span><span class="w" id="mwAT4"> </span><span class="n" id="mwAT8">pi</span><span class="o" id="mwAUA"><</span><span class="k" id="mwAUE">const</span><span class="w" id="mwAUI"> </span><span class="kt" id="mwAUM">char</span><span class="o" id="mwAUQ">*></span><span class="w" id="mwAUU"> </span><span class="o" id="mwAUY">=</span><span class="w" id="mwAUc"> </span><span class="s" id="mwAUg">"pi"</span><span class="p" id="mwAUk">;</span>

Aggregate member initialization

C++11 added default member initializers, expressions to be applied to members at class scope if a constructor did not initialize the member itself. The definition of aggregates was changed to explicitly exclude any class with member initializers; therefore, they are not allowed to use aggregate initialization.

C++14 relaxes this restriction, allowing aggregate initialization on such types. If the braced init list does not provide a value for that argument, the member initializer takes care of it.

Binary literals

Numeric literals in C++14 can be specified in binary form. The syntax uses the prefixes 0b or 0B. The syntax is also used in other languages e.g. Java, C#, Swift, Go, Scala, Ruby, Python, OCaml, and as an unofficial extension in some C compilers since at least 2007.

Digit separators

In C++14, the single-quote character may be used arbitrarily as a digit separator in numeric literals, both integer literals and floating point literals. This can make it easier for human readers to parse large numbers through subitizing.

<span id="mwAWw"></span><span class="k" id="mwAW0">auto</span><span class="w" id="mwAW4"> </span><span class="n" id="mwAW8">integer_literal</span><span class="w" id="mwAXA"> </span><span class="o" id="mwAXE">=</span><span class="w" id="mwAXI"> </span><span class="mi" id="mwAXM">1'000'000</span><span class="p" id="mwAXQ">;</span> <span class="k" id="mwAXU">auto</span><span class="w" id="mwAXY"> </span><span class="n" id="mwAXc">floating_point_literal</span><span class="w" id="mwAXg"> </span><span class="o" id="mwAXk">=</span><span class="w" id="mwAXo"> </span><span class="mf" id="mwAXs">0.000'015'3</span><span class="p" id="mwAXw">;</span> <span class="k" id="mwAX0">auto</span><span class="w" id="mwAX4"> </span><span class="n" id="mwAX8">binary_literal</span><span class="w" id="mwAYA"> </span><span class="o" id="mwAYE">=</span><span class="w" id="mwAYI"> </span><span class="mb" id="mwAYM">0b0100'1100'0110</span><span class="p" id="mwAYQ">;</span> <span class="k" id="mwAYU">auto</span><span class="w" id="mwAYY"> </span><span class="n" id="mwAYc">a_dozen_crores</span><span class="w" id="mwAYg"> </span><span class="o" id="mwAYk">=</span><span class="w" id="mwAYo"> </span><span class="mi" id="mwAYs">12'00'00'000</span><span class="p" id="mwAYw">;</span>

Generic lambdas

In C++11, lambda function parameters need to be declared with concrete types. C++14 relaxes this requirement, allowing lambda function parameters to be declared with the auto type specifier.

<span id="mwAZU"></span><span class="k" id="mwAZY">auto</span><span class="w" id="mwAZc"> </span><span class="n" id="mwAZg">lambda</span><span class="w" id="mwAZk"> </span><span class="o" id="mwAZo">=</span><span class="w" id="mwAZs"> </span><span class="p" id="mwAZw">[](</span><span class="k" id="mwAZ0">auto</span><span class="w" id="mwAZ4"> </span><span class="n" id="mwAZ8">x</span><span class="p" id="mwAaA">,</span><span class="w" id="mwAaE"> </span><span class="k" id="mwAaI">auto</span><span class="w" id="mwAaM"> </span><span class="n" id="mwAaQ">y</span><span class="p" id="mwAaU">)</span><span class="w" id="mwAaY"> </span><span class="p" id="mwAac">{</span><span class="k" id="mwAag">return</span><span class="w" id="mwAak"> </span><span class="n" id="mwAao">x</span><span class="w" id="mwAas"> </span><span class="o" id="mwAaw">+</span><span class="w" id="mwAa0"> </span><span class="n" id="mwAa4">y</span><span class="p" id="mwAa8">;};</span>

Concerning auto type deduction, generic lambdas follow the rules of template argument deduction (which are similar, but not identical in all respects). The code above is equivalent to this:

<span id="mwAbg"></span><span class="k" id="mwAbk">struct</span> <span class="p" id="mwAbo">{</span> <span class="w" id="mwAbs"> </span><span class="k" id="mwAbw">template</span><span class="o" id="mwAb0"><</span><span class="k" id="mwAb4">typename</span><span class="w" id="mwAb8"> </span><span class="nc" id="mwAcA">T</span><span class="p" id="mwAcE">,</span><span class="w" id="mwAcI"> </span><span class="k" id="mwAcM">typename</span><span class="w" id="mwAcQ"> </span><span class="nc" id="mwAcU">U</span><span class="o" id="mwAcY">></span> <span class="w" id="mwAcc"> </span><span class="k" id="mwAcg">auto</span><span class="w" id="mwAck"> </span><span class="k" id="mwAco">operator</span><span class="p" id="mwAcs">()(</span><span class="n" id="mwAcw">T</span><span class="w" id="mwAc0"> </span><span class="n" id="mwAc4">x</span><span class="p" id="mwAc8">,</span><span class="w" id="mwAdA"> </span><span class="n" id="mwAdE">U</span><span class="w" id="mwAdI"> </span><span class="n" id="mwAdM">y</span><span class="p" id="mwAdQ">)</span><span class="w" id="mwAdU"> </span><span class="k" id="mwAdY">const</span><span class="w" id="mwAdc"> </span><span class="p" id="mwAdg">{</span><span class="k" id="mwAdk">return</span><span class="w" id="mwAdo"> </span><span class="n" id="mwAds">x</span><span class="w" id="mwAdw"> </span><span class="o" id="mwAd0">+</span><span class="w" id="mwAd4"> </span><span class="n" id="mwAd8">y</span><span class="p" id="mwAeA">;}</span> <span class="p" id="mwAeE">}</span><span class="w" id="mwAeI"> </span><span class="n" id="mwAeM">lambda</span><span class="p" id="mwAeQ">{};</span>

Generic lambdas are essentially templated functor lambdas.

Lambda capture expressions

C++11 lambda functions capture variables declared in their outer scope by value-copy or by reference. This means that value members of a lambda cannot be move-only types. C++14 allows captured members to be initialized with arbitrary expressions. This allows both capture by value-move and declaring arbitrary members of the lambda, without having a correspondingly named variable in an outer scope.

This is done via the use of an initializer expression:

<span id="mwAe8"></span><span class="k" id="mwAfA">auto</span><span class="w" id="mwAfE"> </span><span class="n" id="mwAfI">lambda</span><span class="w" id="mwAfM"> </span><span class="o" id="mwAfQ">=</span><span class="w" id="mwAfU"> </span><span class="p" id="mwAfY">[</span><span class="n" id="mwAfc">value</span><span class="w" id="mwAfg"> </span><span class="o" id="mwAfk">=</span><span class="w" id="mwAfo"> </span><span class="mi" id="mwAfs">1</span><span class="p" id="mwAfw">]</span><span class="w" id="mwAf0"> </span><span class="p" id="mwAf4">{</span><span class="k" id="mwAf8">return</span><span class="w" id="mwAgA"> </span><span class="n" id="mwAgE">value</span><span class="p" id="mwAgI">;};</span>

The lambda function lambda returns 1, which is what value was initialized with. The declared capture deduces the type from the initializer expression as if by auto.

This can be used to capture by move, via the use of the standard std::move function:

<span id="mwAgs"></span><span class="n" id="mwAgw">std</span><span class="o" id="mwAg0">::</span><span class="n" id="mwAg4">unique_ptr</span><span class="o" id="mwAg8"><</span><span class="kt" id="mwAhA">int</span><span class="o" id="mwAhE">></span><span class="w" id="mwAhI"> </span><span class="n" id="mwAhM">ptr</span><span class="p" id="mwAhQ">(</span><span class="k" id="mwAhU">new</span><span class="w" id="mwAhY"> </span><span class="kt" id="mwAhc">int</span><span class="p" id="mwAhg">(</span><span class="mi" id="mwAhk">10</span><span class="p" id="mwAho">));</span> <span class="k" id="mwAhs">auto</span><span class="w" id="mwAhw"> </span><span class="n" id="mwAh0">lambda</span><span class="w" id="mwAh4"> </span><span class="o" id="mwAh8">=</span><span class="w" id="mwAiA"> </span><span class="p" id="mwAiE">[</span><span class="n" id="mwAiI">value</span><span class="w" id="mwAiM"> </span><span class="o" id="mwAiQ">=</span><span class="w" id="mwAiU"> </span><span class="n" id="mwAiY">std</span><span class="o" id="mwAic">::</span><span class="n" id="mwAig">move</span><span class="p" id="mwAik">(</span><span class="n" id="mwAio">ptr</span><span class="p" id="mwAis">)]</span><span class="w" id="mwAiw"> </span><span class="p" id="mwAi0">{</span><span class="k" id="mwAi4">return</span><span class="w" id="mwAi8"> </span><span class="o" id="mwAjA">*</span><span class="n" id="mwAjE">value</span><span class="p" id="mwAjI">;};</span>

The attribute [[deprecated]]

The deprecated 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. An optional string literal can appear as the argument of deprecated, to explain the rationale for deprecation and suggest a replacement.

<span id="mwAj0"></span><span class="p" id="mwAj4">[[</span><span class="n" id="mwAj8">deprecated</span><span class="p" id="mwAkA">]]</span><span class="w" id="mwAkE"> </span><span class="kt" id="mwAkI">int</span><span class="w" id="mwAkM"> </span><span class="n" id="mwAkQ">f</span><span class="p" id="mwAkU">();</span> <span class="p" id="mwAkY">[[</span><span class="n" id="mwAkc">deprecated</span><span class="p" id="mwAkg">(</span><span class="s" id="mwAkk">"g() is thread-unsafe. Use h() instead"</span><span class="p" id="mwAko">)]]</span> <span class="kt" id="mwAks">void</span><span class="w" id="mwAkw"> </span><span class="n" id="mwAk0">g</span><span class="p" id="mwAk4">(</span><span class="w" id="mwAk8"> </span><span class="kt" id="mwAlA">int</span><span class="o" id="mwAlE">&</span><span class="w" id="mwAlI"> </span><span class="n" id="mwAlM">x</span><span class="w" id="mwAlQ"> </span><span class="p" id="mwAlU">);</span> <span class="kt" id="mwAlY">void</span><span class="w" id="mwAlc"> </span><span class="nf" id="mwAlg">h</span><span class="p" id="mwAlk">(</span><span class="w" id="mwAlo"> </span><span class="kt" id="mwAls">int</span><span class="o" id="mwAlw">&</span><span class="w" id="mwAl0"> </span><span class="n" id="mwAl4">x</span><span class="w" id="mwAl8"> </span><span class="p" id="mwAmA">);</span> <span class="kt" id="mwAmE">void</span><span class="w" id="mwAmI"> </span><span class="nf" id="mwAmM">test</span><span class="p" id="mwAmQ">()</span> <span class="p" id="mwAmU">{</span> <span class="w" id="mwAmY"> </span><span class="kt" id="mwAmc">int</span><span class="w" id="mwAmg"> </span><span class="n" id="mwAmk">a</span><span class="w" id="mwAmo"> </span><span class="o" id="mwAms">=</span><span class="w" id="mwAmw"> </span><span class="n" id="mwAm0">f</span><span class="p" id="mwAm4">();</span><span class="w" id="mwAm8"> </span><span class="c1" id="mwAnA">// warning: 'f' is deprecated</span> <span class="w" id="mwAnE"> </span><span class="n" id="mwAnI">g</span><span class="p" id="mwAnM">(</span><span class="n" id="mwAnQ">a</span><span class="p" id="mwAnU">);</span><span class="w" id="mwAnY"> </span><span class="c1" id="mwAnc">// warning: 'g' is deprecated: g() is thread-unsafe. Use h() instead</span> <span class="p" id="mwAng">}</span>

Sign in to keep reading

2 more chapters are free with a Lably account.

More in Computing and communication