C++ 14 was planned as a minor release to complete the work that produced the C++11 standard, with the aim of becoming a cleaner, simpler, and faster language. Improvements in C++ 14 are “deliberately less” compared to C++ 11, says C++ creator Bjarne Stroustrup.
1. Binary Literals :
Binary literals provide a convenient way to represent a base-2 number. A binary integer literal (base two) begins with 0b or 0B and consists of a sequence of binary digits.
C++ 14 now supports binary literals. It is also possible to separate binary digits with the new ‘ digit separator to separate bytes or nybbles:
// == 65 auto a = 0b100'0001; // == 254 auto b = 0b1111’1110
2. Digit Separator :
The single-quote character ‘ can now be used within a numeric literal for aesthetic readability. It does not affect the numeric value.
auto millions = 1'000'000; auto pi = 3.14159'26535'897;
3. Generic Lambdas :
C++11 requires that lambda parameters to be declared with concrete types but now C++ 14 allows auto type-specifier in the parameter list, enabling polymorphic lambdas.
// C++ 11 auto lambda11 = [ ] (int x, int y) { return x + y; }; // C++ 14 auto lambda14 = [ ] (auto x, auto y) {return x + y;}; // == 12 int twelve = lambda14(3 , 9);
We can now express a lambda that will work with any suitable type:
- This new version can be invoked with any type that has a .size() member function.
- As it also implicitly deduces the return type, the return type will be whatever v.size() returns.
auto v_size = [ ] (const auto& v) { return v.size(); };
4. Generalized Lambda Captures :
This allows creating lambda captures initialized with arbitrary expressions.
int factory(int i) { return i * 10; } // returns 20 auto f = [x = factory(2)] { return x; }; auto generator = [x = 0] () mutable { // this would not compile without 'mutable' // as we are modifying x on each call return x++; }; // == 0 auto a = generator(); // == 1 auto b = generator();
5. Variable Templates :
Existing template syntax is simply added to a variable here. C++ 14 allows constexpr variables to be templated.
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.
template constexpr T pi = T(3.14159265359); template T area_of_circle_with_radius(T r) { return pi * r * r; }
6. Constexpr :
A constexpr-declared function in C++11 is a function which can be executed at compile time to produce a value to be used where a constant expression is required, such as when instantiating a template with an integer argument.
While C++11 constexpr functions could only contain a single expression, C++14 relaxes those restrictions by allowing conditional statements such as if and switch, and also allowing loops, including range-based for loops
C++14 also removes the C++11 rule that constexpr member functions are implicitly const.
C++14 now allows more things inside the body of constexpr functions, notably:
- Local variable declarations (not static or thread_local, and no uninitialized variables).
- Mutating objects whose lifetime began with the constant expression evaluation if, switch, for, while, do-while (not goto).
So in C++14, comparison function generalized to strings can 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; }
7. [ [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.
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data member, a function, an enumeration, or a template specialization.
8. declType (auto) :
The decltype(auto) type-specifier also deduces a type like auto does. However, it deduces return types while keeping their references and cv-qualifiers, while auto will not.
const int a = 0; // int auto a1 = a; // const int decltype(auto) a2 = a; int b = 0; int& b1 = b; // int auto b2 = b1; // int& decltype(auto) b3 = b1; int&& c = 0; // int auto c1 = std::move(c); // int&& decltype(auto) c2 = std::move(c); // Return type is `int`. auto f(const int& i) { return i; } // Return type is `const int&`. decltype(auto) g(const int& i) { return i; }
9. Return type deductions for functions :
C++ 14 allows return type deduction for all functions, thus extending C++ 11 that only allows it for lambda functions:
auto DeduceFunctionReturnType();
Since C++14 is a strongly-typed language, a few restrictions shall be taken into account:
- If a function’s implementation has multiple return statements, they must deduce the same type.
- Return type deduction can be used in forward declarations.
- It works for recursive function as well as long as atleast one return statement precedes the recursive call.
auto f() { // ok return foo() * 42; } auto g() { while( something() ) { if( expr ) { return foo1() * 42; } } return foo2(84); // Multiple returns // (types must be the same) }
Reference –
http://www.open-std.org/jtc1/sc22/wg21/
Please write comments if you find anything incorrect. A gentle request to share this topic on your social media profile.