C++14的这些新特性,你都知道吗?
Posted 凌桓丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++14的这些新特性,你都知道吗?相关的知识,希望对你有一定的参考价值。
文章目录
本文仅介绍 C++ 14 中的一些比较重要的特性。
语言特性
变量模板
变量模板可以将变量实例化成不同的类型,变量模板的定义方法如下所示:
template<class T>
constexpr T pi = T(3.1415926535897932385L); // variable template
template<class T>
T circular_area(T r) // function template
return pi<T> * r * r; // pi<T> is a variable template instantiation
泛型 lambda
在 C++14 中,lambda 表达式参数可以直接是 auto,既泛型 lambda。
// 两个参数
auto glambda = [](auto a, auto&& b) return a < b; ;
bool b = glambda(3, 3.14); // ok
// 单个参数
auto vglambda = [](auto printer)
return [=](auto&&... ts) // 泛型 lambda,ts 是一个参数包
printer(std::forward<decltype(ts)>(ts)...);
return [=] printer(ts...); ; // nullary lambda (不带参数)
;
;
auto p = vglambda([](auto v1, auto v2, auto v3) std::cout << v1 << v2 << v3; );
auto q = p(1, 'a', 3.14); // 输出 1a3.14
q(); // 输出 1a3.14
放宽 constexpr 的限制
C++ 14 中放宽了一些对 constexpr
的限制。如:
- 函数中只能有一个 return 语句。
- 只能使用全局 constexpr 变量。
- 成员函数不能修改非 mutable 数据成员。
因此 constexptr
可以在内部使用局部变量、循环和分支等简单语句,也不再是函数中只能有一个 return 语句。这样就避免了像 C++ 11 中使用 constexpr 时使用大量复杂的三目运算符。
二进制字面量
允许在表达式中直接使用二进制字面量。即 0b 或者 0B 开头的字面量,使用方法如下:
int b = 0b101010; // C++14
数位分隔符
允许在数字之间使用分隔符来提升观感,如下:
unsigned long long l1 = 18446744073709550592ull; // C++11
unsigned long long l2 = 18'446'744'073'709'550'592llu; // C++14
unsigned long long l3 = 1844'6744'0737'0955'0592uLL; // C++14
unsigned long long l4 = 184467'440737'0'95505'92LLU; // C++14
函数返回值类型推导
C++ 14 中对 auto
再次进行优化,使其能够对函数的返回值类型进行推导,如:
int x = 1;
auto f() return x; // 推导返回值为int
const auto& f() return x; // 推导返回值为const int&
但是这也有许多限制,这里就不过多介绍,感兴趣的可以看看直接看官方文档 Function declaration。
库特性
make_unique
在 C++ 11 中只有 make_shared
而没有 make_unique
,在 C++ 14 中则改善了这个问题。
make_unique
用于构造一个类型的对象T并将其包装在 std::unique_ptr
中。
template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args );
用法如下:
struct Test
int x, y, z;
Test(int x = 0, int y = 0, int z = 0) noexcept : x(x), y(y), z(z)
friend std::ostream& operator<<(std::ostream& os, const Test& v)
return os << " x=" << v.x << ", y=" << v.y << ", z=" << v.z << " ";
;
int main()
// 使用全缺省构造函数
std::unique_ptr<Test> v1 = std::make_unique<Test>();
// 加上参数
std::unique_ptr<Test> v2 = std::make_unique<Test>(0, 1, 2);
// 创建unique_ptr数组
std::unique_ptr<Test[]> v3 = std::make_unique<Test[]>(5);
shared_timed_mutex 和 shared_lock
shared_timed_mutex
即共享锁,支持以共享/独占两种模式的加锁。用于读写分明的并发场景。允许在加锁时设置超时时间,如果在规定时间内没有加锁成功则直接返回。(无超时版本的 shared_mutex
在 C++ 17 中实现)
shared_lock
即以共享模式锁定资源(同时以 RAII 管理锁资源),保证多个线程可以同时读,但是写操作互斥,不可以同时和读操作一起进行。
用来配合 shared_timed_mutex
、unique_lock
实现读写锁,例如:
class R
mutable std::shared_timed_mutex mut;
public:
R& operator=(const R& other)
// 配合 unique_lock 实现独占锁
std::unique_lock<std::shared_timed_mutex> lhs(mut, std::defer_lock);
// 配合 shared_lock 实现共享锁
std::shared_lock<std::shared_timed_mutex> rhs(other.mut, std::defer_lock);
std::lock(lhs, rhs);
return *this;
;
int main()
R r;
integer_sequence
integer_sequence
即整数的编译时序列。可以用于推导并展开可变参数类型中作为参数传递给函数的参数包(如 tuple<T...>
)。
// debug 时使用
template<typename T, T... ints>
void print_sequence(std::integer_sequence<T, ints...> int_seq)
std::cout << "The sequence of size " << int_seq.size() << ": ";
((std::cout << ints << ' '),...);
std::cout << '\\n';
// 将数组转换为Tuple
template<typename Array, std::size_t... I>
auto a2t_impl(const Array& a, std::index_sequence<I...>)
return std::make_tuple(a[I]...);
template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
auto a2t(const std::array<T, N>& a)
return a2t_impl(a, Indices);
// 输出一个Tuple
template<class Ch, class Tr, class Tuple, std::size_t... Is>
void print_tuple_impl(std::basic_ostream<Ch,Tr>& os,
const Tuple& t,
std::index_sequence<Is...>)
((os << (Is == 0? "" : ", ") << std::get<Is>(t)), ...);
template<class Ch, class Tr, class... Args>
auto& operator<<(std::basic_ostream<Ch, Tr>& os,
const std::tuple<Args...>& t)
os << "(";
print_tuple_impl(os, t, std::index_sequence_for<Args...>);
return os << ")";
exchange
exchange
使用 new_value 替换 obj 的值,并返回 obj 的旧值。
template< class T, class U = T >
T exchange( T& obj, U&& new_value );
- 类型 T 必须满足可移动构造的要求。而且必须能移动赋值 U 类型对象给 T 类型对象
exchange
通常用于实现移动赋值、移动拷贝语义,如下面这个例子:
struct S
int n;
S(S&& other) noexcept : nstd::exchange(other.n, 0)
S& operator=(S&& other) noexcept
if(this != &other)
n = std::exchange(other.n, 0); // move n, while leaving zero in other.n
return *this;
;
quoted
quoted
用于允许歹用双引号或者其他符号的字符串输入或者输出。
template< class CharT >
/*unspecified*/ quoted( const CharT* s, CharT delim=CharT('"'), CharT escape=CharT('\\\\') );
- delim:分隔符,默认为 “。
- escape:转义字符,默认为 \\\\。
如以下例子:
int main()
string s = "hello world";
cout << s << endl;
cout << quoted(s) << endl;
cout << quoted(s, '?') << endl;
return 0;
输出结果:
hello world
"hello world"
?hello world?
以上是关于C++14的这些新特性,你都知道吗?的主要内容,如果未能解决你的问题,请参考以下文章