C++14

From Wikipedia, the free encyclopedia
Jump to: navigation, search

C++14 is the informal name for the next revision of the C++ ISO/IEC standard. C++14 is planned to be a small extension over C++11, featuring mainly bug fixes and small improvements. The committee draft of the C++14 standard, N3690, was published May 15, 2013.[1] The working draft, N3936, was published March 2, 2014.

While the name "C++14" suggests a release in 2014, this date is not fixed. Therefore the name "C++1y" is sometimes used instead, 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).

The features described below are those described in the Working Draft N3797. They may be changed or removed before final standardization.

New language features[edit]

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

Generic lambdas[edit]

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

auto lambda = [](auto x, auto y) {return x + y;};

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

struct unnamed_lambda
{
  template<typename T, typename U>
    auto operator()(T x, U y) const {return x + y;}
};
auto lambda = unnamed_lambda();

Lambda captures expressions[edit]

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.[4] 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.[2]

This is done via the use of an initializer expression:

auto lambda = [value = 1] {return value;};

The lambda function lambda will return 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:

auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [value = std::move(ptr)] {return *value;};

Function return type deduction[edit]

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;.[5]

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:

auto DeduceReturnType();   // Return type to be determined.

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

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:[6]

auto Correct(int i) {
  if (i == 1)
    return i;               // return type deduced as int
  else
    return Correct(i-1)+i;  // ok to call it now
}
 
auto Wrong(int i)
{
  if(i != 1)
    return Wrong(i-1)+i;  // Too soon to call this. No prior return statement.
  else
    return i;             // return type deduced as int
}

Alternate type deduction on declaration[edit]

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, the way decltype and auto deduce types are different. In particular, auto will always deduce a non-reference type, as though by using std::remove_reference, while auto&& will always deduce 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:[5]

int i;
int&& f();
auto x3a = i;              // decltype(x3a) is int
decltype(i) x3d = i;       // decltype(x3d) is int
auto x4a = (i);            // decltype(x4a) is int
decltype((i)) x4d = (i);   // decltype(x4d) is int&
auto x5a = f();            // decltype(x5a) is int
decltype(f()) x5d = f();   // decltype(x5d) is int&&

C++14 will add 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.[6]

Relaxed constexpr restrictions[edit]

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 will relax these restrictions. Constexpr-declared functions may now contain the following:[5]

  • Any declarations except:
    • static or thread_local variables.
    • Variable declarations without initializers.
  • The conditional branching statements if and switch. goto is not allowed.
  • All looping statements, including range-based for.
  • Expressions may 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.

The restrictions about calling non-constexpr functions remain. So if the range-based for is used, the overload of begin and end must be constexpr themselves. Notably, std::initializer_list has constexpr begin/end functions, both locally and globally.

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.[7] However, per the above restrictions, 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[edit]

In prior versions of C++, only functions, classes or using-declarations could be templated. C++14 now 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.[2][8]

Aggregate member initialization[edit]

C++11 added 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 will relax this restriction,[5] allowing aggregate initialization on such types. If the braced init list does not provide a value for that argument, the member initializer will take care of it.[9]

Binary literals[edit]

Numeric literals in C++14 can be specified in binary form.[5] The syntax uses the prefixes 0b or 0B. The syntax is also used by Java, Python, Perl, and D.

New standard library features[edit]

Shared mutexes and locking[edit]

C++14 adds a shared mutex and a companion shared lock type.[10][11]

Heterogeneous lookup in associative containers[edit]

The C++ standard library defines four associative container classes. These classes allow the user to look up a value based on a value of that type. The map containers allow the user to specify a key and a value, where lookup is done by key and returns a value. However, the lookup is always done by the specific key type, whether it is the key as in maps or the value itself as in sets.

C++14 allows the lookup to be done via an arbitrary type, so long as the comparison operator can compare that type with the actual key type.[12] This would allow a map from std::string to some value to compare against a const char* or any other type for which an operator< overload is available.

To preserve backwards compatibility, heterogeneous lookup is only allowed when the comparator given to the associative container allows it. The standard library classes std::less (the default for sets and maps) and std::greater are augmented to allow heterogeneous lookup.[13]

Standard user-defined literals[edit]

C++11 defined the syntax for user-defined literal suffixes, but the standard library did not use any of them. C++14 adds the following standard literals:[12]

  • "s", for creating the various std::basic_string types.
  • "h", "min", "s", "ms", "us", "ns", for creating the corresponding std::chrono::duration time intervals.
string str = "hello world"s;
chrono::duration dur = 60s;

The two "s" literals do not interact, as the string one only operates on string literals, and the one for seconds operates only on numbers.[14]

Tuple addressing via type[edit]

The std::tuple type introduced in C++11 allows an aggregate of typed values to be indexed by a compile-time constant integer. C++14 will extend this to allow fetching from a tuple by type instead of by index.[12] If the tuple has more than one element of the type, a compiler error will result:[15]

tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t);        // i == 7
int j = get<2>(t);          // Same as before: j == 7
string s = get<string>(t);  // Compiler error due to ambiguity

Smaller library features[edit]

std::make_unique can be used like std::make_shared for std::unique_ptr objects.[2]

std::integral_constant will gain an operator() overload to return the constant value.[12]

The global std::begin/std::end functions will be augmented with std::cbegin/std::cend functions, which return constant beginning/ending iterators of the range.

See also[edit]

References[edit]

  1. ^ "Committee Draft, Standard for Programming Language C++" (PDF). ISO. 15 May 2013. 
  2. ^ a b c d Sutter, Herb (20 April 2013). "Trip Report: ISO C++ Spring 2013 Meeting". isocpp.org. Retrieved 14 June 2013. 
  3. ^ Faisal, Vali; Sutter, Herb; Abrahams, Dave (19 April 2013). "N3649 Generic (Polymorphic) Lambda Expressions (Revision 3)". 
  4. ^ "Move capture in Lambda". Stack Overflow. 
  5. ^ a b c d e Wong, Michael (30 April 2013). "The View from the C++ Standard meeting April 2013 Part 3". C/C++ Cafe. Retrieved 14 June 2013. 
  6. ^ a b c Merrill, Jason (17 April 2013). "N3638 Return type deduction for normal functions (Revision 5)". Retrieved 14 June 2013. 
  7. ^ Smith, Richard (18 April 2013). "N3652 Relaxing constraints on constexpr functions". 
  8. ^ Dos Reis, Gabriel (19 April 2013). "N3651 Variable Templates (Revision 1)" (PDF). 
  9. ^ Vandevoorde, Daveed; Voutilainen, Ville (17 April 2013). "N3653 Member initializers and aggregates". 
  10. ^ Wong, Michael (30 April 2013). "The View from the C++ Standard meeting April 2013 Part 3". C/C++ Cafe. Retrieved 14 June 2013. 
  11. ^ Howard, Hinnant; Vollmann, Detlef; Boehm, Hans (19 April 2013). "N3659 Shared locking in C++ (Revision 2)". 
  12. ^ a b c d Wong, Michael (26 April 2013). "The View from the C++ Standard meeting April 2013 Part 2". C/C++ Cafe. Retrieved 14 June 2013. 
  13. ^ "N3657 Adding heterogeneous comparison lookup to associative containers (rev 4)". 19 March 2013. 
  14. ^ Peter, Sommerlad (18 April 2013). "N3642 User-defined Literals for Standard Library Types (part 1 - version 4)" (PDF). 
  15. ^ Spertus, Mike (19 April 2013). "N3670 Wording for Addressing Tuples by Type: Revision 2".