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.
