C + + standard - C++14 features

Posted by hrdyzlita on Sun, 16 Jan 2022 07:05:48 +0100

1, Variable template

Before C++11, we only had templates for classes and functions. In C++14, a variable template is added:

template<class T>
constexpr T pi = T(3.1415926535897932385L);

template<class T>
T circular_area(T r)
{
	return pi<T> *r * r;
}

Variable templates can also be used in class variables:

template<class T>
class X {
	static T s;
};
template<class T>
T X<T>::s = 0; 

Similar to function and class templates, instantiation occurs when variable templates are referenced.

2, What's new in lambda expressions

1. Generalization

Support the use of auto to define variable types in lambda expressions:

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	auto glambda = [](auto& a) { cout << a << " "; };
	int a[] = { 4, 2, 6, 3, 7, 5 };
	for_each(a, a + sizeof(a) / sizeof(int), glambda);
	cout << endl;
}

2. Initialize captured variables and references

#include <iostream>
using namespace std;

int main()
{
	int x = 4;
	auto y = [&r = x, x = x + 1]()->int
	{
		r += 2;
		return x * x;
	}(); 
	cout << "x = " << x << " y = " << y << endl;
}

3, The constexpr function can contain multiple statements

In C++11, if you want to use the constexpr method, you can only include one return statement. In C++14, this requirement is relaxed, allowing variables to be declared in constexpr function, loops and conditional statements to be used:

#include <iostream>
#include <cmath>
using namespace std;

constexpr bool isPrimitive(int number)
{
	if (number <= 0)
	{
		return false;
	}

	for (int i = 2; i <= sqrt(number) + 1; ++i)
	{
		if (number % i == 0)
		{
			return false;
		}
	}

	return true;
}

int main()
{
	cout << boolalpha << isPrimitive(102) << " " << isPrimitive(103);
	return 0;
}

In C++11, we generally need to achieve the same functions through recursion:

constexpr bool isPrimitive(int number, int currentFactor, int maxFactor)
{
	return currentFactor == maxFactor ? true : 
			(number % currentFactor == 0 ? false : 
				isPrimitive(number, currentFactor + 1, maxFactor));
}

constexpr bool isPrimitive(int number)
{
	return number <= 0 ? false : isPrimitive(number, 2, sqrt(number) + 1);
}

4, Integer literal

1. Binary literal

Integer types that use a string of numbers beginning with 0b as binary representation are supported:

int a = 0b10101001110; // 1358

2. Number separator

Support the use of single quotation marks in numbers for segmentation (easy to read). These single quotes are ignored at compile time.

int a = 123'456'789; // 123456789

5, Automatic derivation of return type

In C++14, we can use auto as the return value of the function without specifying the derived expression of its return type

int x = 1;
auto f() { return x; }
/* c++11
auto f() -> decltype(x) { return x; } 
*/

This type of derivation has some limitations:

  • All return words and sentences in a function must derive the same type;
  • When using the data of {} package as the return value, its type cannot be deduced;
  • Virtual functions and coroutine cannot be deduced;
  • Type derivation can be used in function templates, but its explicit instantiation and specialization versions must use the same return type descriptor.

6, exchange

exchange is used for mobile semantics. You can replace the original value with the specified new value and return the original value. Its definition is simply modified in C++20 as follows:

template<class T, class U = T>
constexpr // since C++20
T exchange(T& obj, U&& new_value)
{
    T old_value = std::move(obj);
    obj = std::forward<U>(new_value);
    return old_value;
}

Its use is as follows:

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

int main()
{
	vector<int> v = {5, 6, 7};

	std::exchange(v, { 1,2,3,4 });

	std::copy(begin(v), end(v), ostream_iterator<int>(cout, " "));
	cout << endl;
}

7, quoted

This class is used for string escape processing. Using the form of out < < quoted (s, delim, escape), the escape format of string s can be written into the output stream; Use in > > quoted (s, delim, escape) to write the input stream to the string s after removing the escape format. Where delim indicates the character to be escaped, and escape indicates the character modifying the transferred character:

#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;

int main()
{
	stringstream ss;
	string in = "String with spaces, and embedded \"quotes\" too";
	string out;

	auto show = [&](const auto& what) 
	{
		&what == &in
			? cout << "read in     [" << in << "]\n"
			<< "stored as   [" << ss.str() << "]\n"
			: cout << "written out [" << out << "]\n\n";
	};

	ss << quoted(in); 
	show(in);
	ss >> quoted(out);
	show(out);

	ss.str(""); 

	in = "String with spaces, and embedded $quotes$ too";
	const char delim{ '$' };
	const char escape{ '%' };

	ss << quoted(in, delim, escape);
	show(in);
	ss >> quoted(out, delim, escape);
	show(out);
}

Topics: C++