c++14的这些新特性,你都知道吗?(代码片段)

凌桓丶 凌桓丶     2023-01-29     150

关键词:

文章目录

本文仅介绍 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_mutexunique_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++20的这些新特性,你都知道吗?(代码片段)

文章目录语言特性三路比较运算符范围for中的初始化语句和初始化器constevalconstint概念(concepts)约束协程模块库特性formatosyncstreamspanendianjthreadsemaphorelatchbarrier位运算库ranges语言特性三路比较运算符三路比较运算符表达式... 查看详情

c++20的这些新特性,你都知道吗?(代码片段)

文章目录语言特性三路比较运算符范围for中的初始化语句和初始化器constevalconstint概念(concepts)约束协程模块库特性formatosyncstreamspanendianjthreadsemaphorelatchbarrier位运算库ranges语言特性三路比较运算符三路比较运算符表达式... 查看详情

c++20的这些新特性,你都知道吗?(代码片段)

文章目录语言特性三路比较运算符范围for中的初始化语句和初始化器constevalconstint概念(concepts)约束协程模块库特性formatosyncstreamspanendianjthreadsemaphorelatchbarrier位运算库ranges语言特性三路比较运算符三路比较运算符表达式... 查看详情

这些关于handler的知识点你都知道吗?(代码片段)

在安卓面试中,关于Handler的问题是必备的,但是这些关于Handler的知识点你都知道吗?一、题目层次Handler的基本原理子线程中怎么使用HandlerMessageQueue获取消息是怎么等待为什么不用wait而用epoll呢?线程和HandlerLoope... 查看详情

@autowired的这些骚操作,你都知道吗?(代码片段)

前言最近review别人代码的时候,看到了一些@Autowired不一样的用法,觉得有些意思,特定花时间研究了一下,收获了不少东西,现在分享给大家。也许@Autowired比你想象中更强大。1.@Autowired的默认装配我... 查看详情

@autowired的这些骚操作,你都知道吗?(代码片段)

hi,大家好,我是苏三,又跟大家见面了。前言最近review别人代码的时候,看到了一些@Autowired不一样的用法,觉得有些意思,特定花时间研究了一下,收获了不少东西,现在分享给大家。也许@... 查看详情

玩转mysql:都2022年了,这些数据库技术你都知道吗(代码片段)

引言MySQL数据库从1995年诞生至今,已经过去了二十多个年头了,到2022.04.26日为止,MySQL8.0.29正式发行了GA版本,在此之前版本也发生了多次迭代,发行了大大小小N多个版本,其中每个版本中都有各自的新特... 查看详情

java中的基本数据类型和包装类型的这些知识,你都知道吗?(代码片段)

Java中的基本数据类型和包装类型Java中的基本数据按类型可以分为四大类:布尔型、整数型、浮点型、字符型;这四大类包含8种基本数据类型。布尔型:boolean整数型:byte、short、int、long浮点型:float、double字符型:char这8种基本... 查看详情

java开发人员必知的常用类库,这些你都知道吗?(代码片段)

作为一名程序员,我们要避免重复发明轮子,尽可能使用一些成熟、优秀、稳定的的第三方库,站在巨人的肩膀上搭建可靠、稳定的系统。本篇我整理了Java开发人员经常会使用到的第三方类库,可能不是很全面,还在持续收集... 查看详情

c++14新特性大全更加智能的auto(代码片段)

函数返回值类型推导C++14对函数返回类型推导规则做了优化,先看一段代码:#include<iostream>usingnamespacestd;autofunc(inti)returni;intmain()cout<<func(4)<<endl;return0;使用C++11编译:~/t 查看详情

c++14新特性增加二进制字面值(代码片段)

...在C++11的标准上增加了两个让人有那么点小兴奋的特性:1. 查看详情

c++14新特性增加二进制字面值(代码片段)

...在C++11的标准上增加了两个让人有那么点小兴奋的特性:1. 查看详情

javascript中的这些骚操作,你都知道吗?

引言 查看详情

c++14新特性[[deprecated]]标记(代码片段)

https://en.cppreference.com/w/cpp/language/attributes/deprecatedC++14中增加了[[deprecated]]标记,可以修饰类、函数、变量等,当程序中使用了被其修饰的模块时,编译器会产生告警,提示用户该标记标记的内容将来可能会被... 查看详情

c++14新特性[[deprecated]]标记(代码片段)

https://en.cppreference.com/w/cpp/language/attributes/deprecatedC++14中增加了[[deprecated]]标记,可以修饰类、函数、变量等,当程序中使用了被其修饰的模块时,编译器会产生告警,提示用户该标记标记的内容将来可能会被... 查看详情

c++14新特性[[deprecated]]标记(代码片段)

https://en.cppreference.com/w/cpp/language/attributes/deprecatedC++14中增加了[[deprecated]]标记,可以修饰类、函数、变量等,当程序中使用了被其修饰的模块时,编译器会产生告警,提示用户该标记标记的内容将来可能会被... 查看详情

天天写sql,这些神奇的特性你知道吗?(代码片段)

摘要:不要歪了,我这里说特性它不是bug,而是故意设计的机制或语法,你有可能天天写语句或许还没发现原来还能这样用,没关系我们一起学下涨姿势。本文分享自华为云社区《【云驻共创】天天写SQL,... 查看详情

赶紧收藏!这些java中的流程控制知识你都不知道,你凭什么涨薪?(代码片段)

Java的流程控制基础阶段目录:用户交互Scanner顺序结构选择结构循环结构break&continue练习题1.Scanner对象之前我们学的基本语法中并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入。Java.... 查看详情