C++标准 — C++14特性
一、变量模板
在C++11及之前,我们只有针对类和函数的模板。C++14中,新增了变量模板:
template<class T>
constexpr T pi = T(3.1415926535897932385L);
template<class T>
T circular_area(T r)
{
return pi<T> *r * r;
}
变量模板同样可以在类变量中使用:
template<class T>
class X {
static T s;
};
template<class T>
T X<T>::s = 0;
类似函数和类模板,当变量模板被引用时,则会发生实例化。
二、lambda 表达式的新增功能
1、泛化
支持在 lambda 表达式中使用 auto 定义变量类型:
#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、对捕获的变量和引用进行初始化
#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;
}
三、constexpr 函数可以包含多个语句
在C++11中,如果想使用 constexpr 方法,只能包含一个返回语句。C++14中,放宽了此要求,允许 constexpr 函数中声明变量,使用循环和条件语句等:
#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;
}
在C++11中,我们一般需要通过递归来实现相同的功能:
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);
}
四、整型字面量
1、二进制字面量
支持使用 0b 开头的一串数字作为二进制表示的整型:
int a = 0b10101001110; // 1358
2、数字分割符
支持在数字中使用单引号进行分割(便于阅读)。在编译时,这些单引号会被忽略。
int a = 123'456'789; // 123456789
五、返回类型自动推导
在C++14中,我们可以使用 auto 作为函数返回值并且不需要指明其返回类型的推导表达式
int x = 1;
auto f() { return x; }
/* c++11
auto f() -> decltype(x) { return x; }
*/
这种类型推导有一些限制:
- 一个函数中所有返回字句必须推导出相同的类型;
- 使用 {} 包裹的数据作为返回值时,无法推导其类型;
- 虚函数和 coroutine 不能被推导;
- 函数模板中可以使用类型推导,但是其显式实例化和特化版本必须使用相同的返回类型描述符。
六、exchange
exchange 用于移动语义,可以使用指定的新值替换掉原值,并返回原值。其定义在C++20中被简单修改如下:
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;
}
其使用如下:
#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;
}
七、quoted
该类用于字符串转义的处理。使用 out << quoted(s, delim, escape) 的形式,可以将字符串 s 的转义格式写入输出流中;使用 in >> quoted(s, delim, escape) 可以将输入流去除转义格式后写入字符串 s 中。其中,delim 指明了需要转义的字符,escape 指明了修饰该转移字符的字符:
#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);
}