前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++14新增特性汇总

C++14新增特性汇总

作者头像
CPP开发前沿
发布2021-11-16 14:24:17
4600
发布2021-11-16 14:24:17
举报
文章被收录于专栏:CPP开发前沿CPP开发前沿

C++14整体来说只是发行的一个小版本,在C++11大版本的基础上做了一些优化和缺陷的修复。C++14在2014年8月18日正式批准宣布,同年12月15日正式发布release版本。本文中将就变动部分做一个总结,有需要改进和提升的地方希望大家批评指正。

1 变量模板

变量模板是C++14中新增的特性,可以将变量实例化成不同的类型,变量模板的定义方法如下所示:

代码语言:javascript
复制
template < 形参列表 > 变量声明

在上面的语法中,变量声明即为变量模板名,形参列表可以有一个或者多个,使用方法如下:

代码语言:javascript
复制
template<class T>
constexpr T pi = T(3.1415926535897932385L);  // 变量模板

在实际编码中,C++14以前如果要实现上面的功能,需要通过函数模板的方式得到。如下面的代码可以得到相同的功能:

代码语言:javascript
复制
template<class T>
6  std::make_unique方法 T Pi()
{
  return T(3.1415926535897932385L);
}

2 变量模板

在编程时以auto为形参类型时,既可以认为是泛型lambda。

在C++14中,泛型lambda是普通lambda的升级版,具体使用方法如下:

2.1 有两个形参的

代码语言:javascript
复制
int main () {
 auto glambda = [](auto a, auto&& b) { return a < b; };
 bool b = glambda(3, 3.14); 
 std::cout<<"b="<<b<<std::endl;
  return 0;
}

2.2 有1个形参的

代码语言:javascript
复制
int main () {
// 泛型 lambda,operator() 是有一个形参的模板
auto vglambda = [](auto printer) {
    return [=](auto&&... ts) // 泛型 lambda,ts 是形参包
    { 
        printer(std::forward<decltype(ts)>(ts)...);
        return [=] { printer(ts...); }; // 零元 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();    
  return 0;
}

2.3 无捕获的泛型

代码语言:javascript
复制
int main () {
    auto func1 = [](auto i) { return i + 4; };
    std::cout << "func1: " << func1(6) << '\n';
    return 0;
}

代码输出值:10

上面的的代码也可以修改成lambda表达式形参中有默认值的类型,从C++14起,也支持这种写法,代码稍微修改后,程序如下:

代码语言:javascript
复制
int main () {
    auto func1 = [](int i = 6) { return i + 4; };
    std::cout << "func1: " << func1() << '\n';
    return 0;
}

运行此代码,可以运行结果和上面一致。

3 constexpr放松限制

使用constexpr-描述符后,指定的变量或函数的值可以在常量表达式中使用。

在C++11中,constexpr只能只用递归,C++14后进行了优化和提升,可以使用局部变量和循环。且不用将所有的语句放在一条return语句中进行编写。

代码语言:javascript
复制
constexpr int add(int a,int b)
{
    int sum = 0;
    if(a<=0) return -1;
    if(b<=0) return -1;
    sum = a+b;
    return sum;
}
int main () {
    std::cout<<add(4,6)<<std::endl;
    return 0;
}

如上面代码所示,在C++14之前constexpr是不支持的。

4 二进制字面量

C++14中新增了0b或者0B开头的字面量,使用方法如下:

代码语言:javascript
复制
int main () {
   int x=32;
   int y = 0b100000;
   std::cout<<(x==y)<<std::endl;
    return 0;
}

代码输出结果为:1

5 函数返回值推导

在C++11中使用后置类型推导函数返回值,C++14起,可以省略,返回值使用auto,编译器直接将函数体中的return语句值类型推导。使用时需要注意的是:

  • 如果有多条return语句,每条的返回值类型需要保持一致。
  • 如果没有返回语句或返回语句的实参是 void 表达式,那么所声明的返回类型,必须是 decltype(auto)或者auto,此时推导出的返回类型是void。
  • 一旦在函数中见到一条返回语句,那么从该语句推导的返回类型就可以用于函数的剩余部分。
  • 如果返回语句使用花括号初始化器列表(brace-init-list),那么不允许推导。

使用方法见如下代码:

代码语言:javascript
复制
//C++14中不需要后置
auto add(int x, int y)
{
  return x + y;
}
//多条返回语句返回值类型保持一致
auto f(bool val)
{
    if(val) return 123;   // 推导返回类型 int
    else return 3.14f;    // 错误:推导返回类型 float
}
//必须有条返回语句可以推导出来返回类型并用在后面的语句
auto sum(int i)
{
    if(i == 1)
        return i;              // sum 的返回类型是 int
    else
        return sum(i - 1) + i; // OK,sum 的返回类型已知
}
//返回值使用{}不允许推导
auto func () { return {1, 2, 3}; } // 错误

6 std::make_unipue方法

C++14提供了std::make_unique方法.使用方法如下:

代码语言:javascript
复制
#include <iostream>
#include <memory>
 
struct Vec3
{
    int x, y, z;
    // C++20 起不再需要以下构造函数
    Vec3(int x = 0, int y = 0, int z = 0) noexcept : x(x), y(y), z(z) { }
    friend std::ostream& operator<<(std::ostream& os, const Vec3& v)
    {
        return os << '{' << "x:" << v.x << " y:" << v.y << " z:" << v.z  << '}';
    }
};
 
int main()
{
    // 使用默认构造函数。
    std::unique_ptr<Vec3> v1 = std::make_unique<Vec3>();
    // 使用匹配这些参数的构造函数
    std::unique_ptr<Vec3> v2 = std::make_unique<Vec3>(0, 1, 2);
    // 创建指向 5 个元素数组的 unique_ptr 
    std::unique_ptr<Vec3[]> v3 = std::make_unique<Vec3[]>(5);
 
    std::cout << "make_unique<Vec3>():      " << *v1 << '\n'
              << "make_unique<Vec3>(0,1,2): " << *v2 << '\n'
              << "make_unique<Vec3[]>(5):   " << '\n';
    for (int i = 0; i < 5; i++) {
        std::cout << "     " << v3[i] << '\n';
    }
}

7 std::shared_timed_mutex、std::share_lock

共享互斥的使用使用场景是同一个数据资源,存在多个线程读,但只有一个线程可以进行修改的场景。如下面的代码,实现的功能是赋值运算符可以有多个读但是只有一个写能力

代码语言:javascript
复制
class R
{
    mutable std::shared_timed_mutex mut;
    /* 数据 */
public:
    R& operator=(const R& other)
    {
        // 要求排他性所有权以写入 *this
        std::unique_lock<std::shared_timed_mutex> lhs(mut, std::defer_lock);
        // 要求共享所有权以读取 other
        std::shared_lock<std::shared_timed_mutex> rhs(other.mut, std::defer_lock);
        std::lock(lhs, rhs);
        /* 赋值数据 */
        return *this;
    }
};
int main() {
    R r;
}

8 std::integer_sequence类

使用时需要包含头文件 <utility>,定义原型为:

代码语言:javascript
复制
template< class T, T... Ints >
struct integer_sequence;

有一个公开静态成员函数size,返回Ints的个数。改类使用方法为:

代码语言:javascript
复制
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';
}
int main()
{
    print_sequence(std::integer_sequence<unsigned, 9, 2, 5, 1, 9, 1, 6>{});
    return 0;
}

代码输出结果为:The sequence of size 7: 9,2,5,1,9,1,6,

9 std::exchange类

函数原型为:

代码语言:javascript
复制
template< class T, class U = T >
T exchange( T& obj, U&& new_value );

表示使用new_value替换obj,同时返回返回obj。如下面代码所示:

代码语言:javascript
复制
void f() { std::cout << "f()"; }
 
int main()
{
   std::vector<int> v;
   std::exchange(v, {1,2,3,4});
   std::copy(begin(v),end(v), std::ostream_iterator<int>(std::cout,", "));
   std::cout << "\n\n";
   void (*fun)();
   std::exchange(fun,f);
   fun();
}

上面代码运行结果为:

代码语言:javascript
复制
1, 2, 3, 4, 
f()

10 std::quoted类

函数原型为:

代码语言:javascript
复制
template< class CharT >
/*unspecified*/ quoted(const CharT* s,
                       CharT delim=CharT('"'), CharT escape=CharT('\\'));

实现功能是可以允许带有双引号或者其他符号字符串输入或者输出。如下面代码所示:

代码语言:javascript
复制
int main()
{
    std::string in = "String with spaces, and embedded \"quotes\" too";
    std::cout<<std::quoted(in)<<std::endl;
    in = "String with spaces, and embedded $quotes$ too";
    const char delim {'$'};
    const char escape {'%'};
    std::cout << std::quoted(in, delim, escape);
}

上述代码输出为:

代码语言:javascript
复制
"String with spaces, and embedded \"quotes\" too"
$String with spaces, and embedded %$quotes%$ too$

如上为C++14中新增的主要特性,当然,还有一些其它的提升,这里将不再进行阐述。如果大家有兴趣欢迎留言讨论。

参考:

https://en.cppreference.com/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP开发前沿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档