激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C/C++ - C++17新特性個(gè)人總結(jié)

C++17新特性個(gè)人總結(jié)

2021-09-16 14:26岸居仔 C/C++

這篇文章主要介紹了C++17新特性個(gè)人總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

C++17

編譯器版本:GCC 7.1、Clang 5.0

__cplusplus:201703L

編譯選項(xiàng):-std=c++17

1 關(guān)鍵字

1.1 constexpr

擴(kuò)展constexpr使用范圍,可用于if語句中,也可用于lambda表達(dá)式中。

例子1:

#include<iostream>
 
template<bool ok>
constexpr void foo()
{
 //在編譯期進(jìn)行判斷,if和else語句不生成代碼
 if constexpr (ok == true)
 {
  //當(dāng)ok為true時(shí),下面的else塊不生成匯編代碼
  std::cout << "ok" << std::endl;
 }
 else
 {
  //當(dāng)ok為false時(shí),上面的if塊不生成匯編代碼
  std::cout << "not ok" << std::endl;
 }
}
 
int main()
{
 foo<true>();//輸出ok,并且匯編代碼中只有std::cout << "ok" << std::endl;這一句
 foo<false>();//輸出not ok,并且匯編代碼中只有std::cout << "not ok" << std::endl;這一句
 return 0;
}

例子2:

int main()
{
 constexpr auto add1 = [](int n, int m){
  auto func1 = [=] { return n; }; //func1 lambda表達(dá)式
  auto func2 = [=] { return m; }; //func2 lambda表達(dá)式
  return [=] { return func1() + func2(); };
 };
 constexpr auto add2 = [](int n, int m){
  return n + m;
 };
 auto add3 = [](int n, int m){
  return n + m;
 };
 int sum1 = add1(30, 40)( ); //傳入常量值,add1在編譯期計(jì)算,立即返回70
 int sum2 = add2(sum1, 4); //由于傳入非constexpr變量,add2的constexpr失效,變成運(yùn)行期lambda
 constexpr int sum3 = add3(1, 2); //sum3為constexpr變量,傳入常量值,add3變成編譯期lambda,立即返回3
 int sum4 = add2(10, 2);//傳入常量值,add2在編譯期計(jì)算,立即返回12
 return 0;
}

1.2 static_assert

擴(kuò)展static_assert用法,靜態(tài)斷言的顯示文本可選。

如:

static_assert(true, "");
static_assert(true);//c++17支持

1.3 auto

擴(kuò)展auto的推斷范圍

如:

auto x1 = { 1, 2 }; //推斷出std::initializer_list<int>類型
auto x2 = { 1, 2.0 }; //錯(cuò)誤:類型不統(tǒng)一,無法推斷
auto x3{ 1, 2 }; //錯(cuò)誤:auto的聚合初始化只能一個(gè)元素
auto x4 = { 3 }; //推斷出std::initializer_list<int>類型
auto x5{ 3 }; //推斷出int類型

1.4 typename

擴(kuò)展用法,允許出現(xiàn)在模板的模板的參數(shù)中。

首先回顧一下typename的用法,①用于模板中,表示模板參數(shù)為類型;②用于聲明某名字是變量名

如例1:

struct A
{
 typedef int Example;
};
//第一種用法:聲明模板參數(shù)為類型
template<typename T>
struct B { };
 
struct C
{
 typedef typename A::Example E;//第二種用法:聲明某名字為一種類型
};
 
int main()
{
 typename A::Example e;//第二種用法:聲明某名字為一種類型
 return 0;
}

新特性下的typename用法,

如例2:

#include<iostream>
#include<typeinfo>
 
template<typename T>
struct A
{
 int num;
 A()
 {
  std::cout << "A Construct" << std::endl;
  std::cout << "template typename is: " << typeid (T).name() << std::endl;
 }
};
//此處的T可省略,X代表模板類型,T和X前的typename可替換成class
template<template<typename T> typename X>
struct B
{
 X<double> e;
 B() { std::cout << "B Construct" << std::endl; }
};
 
int main()
{
 A<B<A>> a;
 std::cout << "***************************" << std::endl;
 B<A> b;
 return 0;
}

運(yùn)行結(jié)果:

C++17新特性個(gè)人總結(jié)

1.5 inline

擴(kuò)展用法,可用于定義內(nèi)聯(lián)變量,功能與內(nèi)聯(lián)函數(shù)相似。inline可避免函數(shù)或變量多重定義的問題,如果已定義相同的函數(shù)或變量(且該函數(shù)或變量聲明為inline),編譯器會(huì)自動(dòng)鏈接到該函數(shù)或變量。

如(不發(fā)生錯(cuò)誤):

// test.h
inline void print()
{
 std::cout << "hello world" << std::endl;
}
 
inline int num = 0;
// func.h
include "test.h"
inline void add(int arg)
{
 num += arg;
 print();
}
// main.cpp
include "func.h"
int main()
{
 num = 0;
 print();
 add(10);
 return 0;
}

2 語法

2.1 折疊表達(dá)式

用于變長參數(shù)模板的解包,只支持各種運(yùn)算符(和操作符),分左、右折疊

如:

#include<string>
 
template<typename ... T>
auto sum(T ... arg)
{
 return (arg + ...);//右折疊
}
 
template<typename ... T>
double sum_strong(T ... arg)
{
 return (arg + ... + 0);//右折疊
}
 
template<typename ... T>
double sub1(T ... arg)
{
 return (arg - ...);//右折疊
}
 
template<typename ... T>
double sub2(T ... arg)
{
 return (... - arg);//左折疊
}
 
int main()
{
 int s1 = sum(1, 2, 2, 4, 5);//解包:((((1+)2+)3+)4+)5 = 15
 double s2 = sum(1.1, 2.2, 3.3, 4.4, 5.5, 6.6);
 double s3 = sum(1, 2.2, 3, 4.4, 5);
 
 double s4 = sub1(5, 2, 1, 1);//解包:((((5-)2-)1-)1) = 1
 double s5 = sub2(5, 2, 1, 1);//解包:(5-(2-(1-(1)))) = 3
 
 double s6 = sum_strong();//s6 = 0
 
 std::string str1("he");
 std::string str2("ll");
 std::string str3("o ");
 std::string str4("world");
 std::string str5 = sum(str1, str2, str3, str4);//str5 = "hello world"
 return 0;
}

2.2 結(jié)構(gòu)化綁定

用一對包含一個(gè)或多個(gè)變量的中括號,表示結(jié)構(gòu)化綁定,但是使用結(jié)構(gòu)化綁定時(shí),須用auto關(guān)鍵字,即綁定時(shí)聲明變量

例子1:

/*
 * 例子:多值返回
 */
struct S
{
 double num1;
 long num2;
};
 
S foo(int arg1, double arg2)
{
 double result1 = arg1 * arg2;
 long result2 = arg2 / arg1;
 return {result1, result2};//返回結(jié)構(gòu)體S對象
};
 
int main()
{
 auto [num1, num2] = foo(10, 20.2);//自動(dòng)推導(dǎo)num1為double,num2為long
 return 0;
}

例子2:

#include<list>
#include<map>
 
/*
 * 例子:循環(huán)遍歷
 */
template<typename T, typename U>
struct MyStruct
{
 T key;
 U value;
};
 
int main()
{
 std::list<MyStruct<int, double>> Container1;
 std::map<int, MyStruct<long long, char>> Container2;
 for(auto [key, value] : Container1)
 {
  //key為int類型,value為double類型
 }
 for(auto [key, value] : Container2)
 {
  //key為int類型,value為MyStruct<long long, char>類型
  //value1為long long類型,value2為char類型
  auto [value1, value2] = value;
 }
 return 0;
}

2.3 允許非類型模板參數(shù)進(jìn)行常量計(jì)算

非類型模板參數(shù)可傳入類的靜態(tài)成員

如:

class MyClass
{
public:
 static int a;
};
 
template<int *arg>
void foo() {}
 
int main()
{
 foo<&MyClass::a>();
 return 0;
}

2.4 條件分支語句初始化

在if和switch中可進(jìn)行初始化

如:

template<long value>
void foo(int &ok)
{
 if constexpr (ok = 10; value > 0)
 {
 
 }
}
 
int main()
{
 int num = 0;
 if(int i = 0; i == 0)
 {
 
 }
 foo<10>(num);
 switch(int k = 10; k)
 {
  case 0:break;
  case 1:break;
  default:break;
 }
 return 0;
}

2.5 聚合初始化

在初始化對象時(shí),可用花括號進(jìn)行對其成員進(jìn)行賦值

如:

struct MyStruct1
{
 int a;
 int b;
};
 
struct MyStruct2
{
 int a;
 MyStruct1 ms;
};
 
int main()
{
 MyStruct1 a{10};
 MyStruct2 b{10, 20};
 MyStruct2 c{1, {}};
 MyStruct2 d{{}, {}};
 MyStruct2 e{{}, {1, 2}};
 return 0;
}

2.6 嵌套命名空間

簡化多層命名空間的寫法

如:

//傳統(tǒng)寫法
namespace A
{
 namespace B
 {
  namespace C
  {
 
  };
 };
};
//新寫法
namespace A::B::C
{
 
};

2.7 lambda表達(dá)式捕獲*this的值

lambda表達(dá)式可捕獲*this的值,但this及其成員為只讀

如:

struct MyStruct {
 double ohseven = 100.7;
 auto f() {
  return [this] {
   return [*this] {
    this->ohseven = 200.2;//錯(cuò)誤,只讀變量不可賦值
    return ohseven;//正確
   };
  }();
 }
 auto g() {
  return []{
   return [*this]{};//錯(cuò)誤,外層lambda表達(dá)式?jīng)]有捕獲this
  }();
 }
};

2.8 枚舉[類]對象的構(gòu)造

可以給枚舉[類]對象賦值

如:

enum MyEnum { value };
MyEnum me {10};//錯(cuò)誤:不能用int右值初始化MyEnum類型對象
 
enum byte : unsigned char { };
byte b { 42 }; //正確
byte c = { 42 }; //錯(cuò)誤:不能用int右值初始化byte類型對象
byte d = byte{ 42 }; //正確,其值與b相等
byte e { -1 }; //錯(cuò)誤:常量表達(dá)式-1不能縮小范圍為byte類型
 
struct A { byte b; };
A a1 = { { 42 } }; //錯(cuò)誤:不能用int右值初始化byte類型對象
A a2 = { byte{ 42 } }; //正確
 
void f(byte);
f({ 42 }); //錯(cuò)誤:無類型說明符
 
enum class Handle : unsigned int { value = 0 };
Handle h { 42 }; //正確

2.9 十六進(jìn)制單精度浮點(diǎn)數(shù)字面值

以0x前綴開頭的十六進(jìn)制數(shù),以f后綴的單精度浮點(diǎn)數(shù),合并,就有了十六進(jìn)制的單精度浮點(diǎn)數(shù)

如:

int main()
{
 float value = 0x1111f;
 return 0;
}

2.10 基于對齊內(nèi)存的動(dòng)態(tài)內(nèi)存分配

談到動(dòng)態(tài)內(nèi)存分配,少不了new和delete運(yùn)算符,新標(biāo)準(zhǔn)中的new和delete運(yùn)算符新增了按照對齊內(nèi)存值來分配、釋放內(nèi)存空間的功能(即一個(gè)新的帶對齊內(nèi)存值的new、delete運(yùn)算符重載)

函數(shù)原型:

void* operator new(std::size_t size, std::align_val_t alignment);
void* operator new[](std::size_t size, std::align_val_t alignment);
 
void operator delete(void*, std::size_t size, std::align_val_t alignment);
void operator delete[](void*, std::size_t size, std::align_val_t alignment);

參數(shù)說明:

size —— 分配的字節(jié)數(shù)。必須為alignment的整數(shù)倍。

alignment —— 指定的對齊內(nèi)存值。必須是實(shí)現(xiàn)支持的合法對齊。

new的返回值:

成功,返回指向新分配內(nèi)存起始地址的指針。

用法例子:

#include<new>
 
struct alignas(8) A {};
 
int main()
{
 A *a = static_cast<A *>(::operator new(sizeof(A), static_cast<std::align_val_t>(alignof (A))));
 ::operator delete(a, sizeof(A), static_cast<std::align_val_t>(alignof (A)));
 return 0;
}

2.11 細(xì)化表達(dá)式的計(jì)算順序

為了支持泛型編程和重載運(yùn)算符的廣泛使用,新特性將計(jì)算順序進(jìn)行的細(xì)化

如以下爭議代碼段:

#include<map>
 
int main()
{
 std::map<int, int> tmp;
 //對于std::map的[]運(yùn)算符重載函數(shù),在使用[]新增key時(shí),std::map就已經(jīng)插入了一個(gè)新的鍵值對
 tmp[0] = tmp.size();//此處不知道插入的是{0, 0}還是{0, 1}
 return 0;
}

為了解決該情況,新計(jì)算順序規(guī)則為:

①后綴表達(dá)式從左到右求值。這包括函數(shù)調(diào)用和成員選擇表達(dá)式。

②賦值表達(dá)式從右向左求值。這包括復(fù)合賦值。

③從左到右計(jì)算移位操作符的操作數(shù)。

2.12 模板類的模板參數(shù)自動(dòng)推導(dǎo)

定義模板類的對象時(shí),可以不指定模板參數(shù),但必須要在構(gòu)造函數(shù)中能推導(dǎo)出模板參數(shù)

如:

template<class T> struct A {
 explicit A(const T&, ...) noexcept {} // #1
 A(T&&, ...){} // #2
};
 
int i;

A a1 = { i, i }; //錯(cuò)誤,不能根據(jù)#1推導(dǎo)為右值引用,也不能通過#1實(shí)現(xiàn)復(fù)制初始化
A a2{i, i}; //正確,調(diào)用#1初始化成功,a2推導(dǎo)為A<int>類型
A a3{0, i}; //正確,調(diào)用#2初始化成功,a2推導(dǎo)為A<int>類型
A a4 = {0, i}; //正確,調(diào)用#2初始化成功,a2推導(dǎo)為A<int>類型

template<class T> A(const T&, const T&) -> A<T&>; // #3
template<class T> explicit A(T&&, T&&) -> A<T>; // #4

A a5 = {0, 1}; //錯(cuò)誤,#1和#2構(gòu)造函數(shù)結(jié)果相同(即沖突)。根據(jù)#3推導(dǎo)為A<int&>類型
A a6{0, 1}; //正確,通過#2推斷為A<int>類型
A a7 = {0, i}; //錯(cuò)誤,不能將非靜態(tài)左值引用綁定到右值。根據(jù)#3推導(dǎo)為A<int&>類型
A a8{0, i}; //錯(cuò)誤,不能將非靜態(tài)左值引用綁定到右值。根據(jù)#3推導(dǎo)為A<int&>類型

template<class T> 
struct B {
 
 template<class U> 
 using TA = T;//定義別名
 
 template<class U> 
 B(U, TA<U>);//構(gòu)造函數(shù)
};

B b{(int*)0, (char*)0}; //正確,推導(dǎo)為B<char *>類型
2.13 簡化重復(fù)命名空間的屬性列表
如:

[[ using CC: opt(1), debug ]] void f() {}
//作用相同于 [[ CC::opt(1), CC::debug ]] void f() {}

2.14 不支持、非標(biāo)準(zhǔn)的屬性

在添加屬性列表時(shí),編譯器會(huì)忽略不支持的非標(biāo)準(zhǔn)的屬性,不會(huì)發(fā)出警告和錯(cuò)誤。

2.15 改寫與繼承構(gòu)造函數(shù)

在類的繼承體系中,構(gòu)造函數(shù)的自動(dòng)調(diào)用是一個(gè)令人頭疼的問題。新特性引入繼承與改寫構(gòu)造函數(shù)的用法。

例子1:

#include<iostream>
 
struct B1
{
 B1(int) { std::cout << "B1" << std::endl; }
};
 
struct D1 : B1 {
 using B1::B1;//表示繼承B1的構(gòu)造函數(shù)
};
 
D1 d1(0); //正確,委托基類構(gòu)造函數(shù)進(jìn)行初始化,調(diào)用B1::B1(int)

例子2:

#include<iostream>
 
struct B1
{
 B1(int) { std::cout << "B1" << std::endl; }
};
 
struct B2
{
 B2(int) { std::cout << "B2" << std::endl; }
};
 
struct D1 : B1, B2 {
 using B1::B1;//表示繼承B1的構(gòu)造函數(shù)
 using B2::B2;//表示繼承B2的構(gòu)造函數(shù)
};
D1 d1(0); //錯(cuò)誤:函數(shù)沖突,
 
struct D2 : B1, B2
{
 using B1::B1;
 using B2::B2;
 //正確,D2::D2(int)隱藏了B1::B1(int)和B2::B2(int)。另外由于B1和B2沒有默認(rèn)的構(gòu)造函數(shù),因此必須顯式調(diào)用B1和B2的構(gòu)造函數(shù)
 D2(int) : B1(1), B2(0)
 { std::cout << "D2" << std::endl; }
};
 
struct D3 : B1 
{
 using B1::B1;
};
D3 d3(0);//正確,繼承B1的構(gòu)造函數(shù),即利用B1的構(gòu)造函數(shù)來初始化,輸出B1
 
// 程序入口
int main()
{
 D2 d(100);//編譯通過,輸出B1 B2 D2
 return 0;
}

例子3:

#include<iostream>
 
struct B1
{
 B1() { std::cout << "B1 default" << std::endl; }
 B1(int) { std::cout << "B1" << std::endl; }
};
 
struct B2
{
 B2() { std::cout << "B2 default" << std::endl; }
 B2(int) { std::cout << "B2" << std::endl; }
};
 
struct D1 : B1, B2
{
 using B1::B1;
 using B2::B2;
 //正確,D2::D2(int)隱藏了B1::B1(int)和B2::B2(int),但必須要顯示調(diào)用B1和B2的構(gòu)造函數(shù)
 D1(int) : B1(1), B2(0)
 { std::cout << "D2" << std::endl; }
 //有默認(rèn)構(gòu)造函數(shù),在不顯示調(diào)用基類的構(gòu)造函數(shù)時(shí)自動(dòng)調(diào)用基類的默認(rèn)構(gòu)造函數(shù)
 D1() { std::cout << "D2 default" << std::endl; }
};
// 程序入口
int main()
{
 D1 d(100);//編譯通過,輸出B1 B2 D2
 D1 dd;
 //輸出
 //B1 default
 //B2 default
 //D2 default
 return 0;
}

2.16 內(nèi)聯(lián)變量

見1.5

2.17 用auto作為非類型模板參數(shù)

當(dāng)模板參數(shù)為非類型時(shí),可用auto自動(dòng)推導(dǎo)類型

如:

#include<iostream>
 
template<auto T>
void foo()
{
 std::cout << T << std::endl;
}
 
int main()
{
 foo<100>();//輸出100
 foo<int>();//no matching function for call to "foo<int>()"
 return 0;
}

3 宏

3.1 __has_include

判斷有沒有包含某文件

如:

int main()
{
#if __has_include(<cstdio>)
 printf("hehe");
#endif
#if __has_include("iostream")
 std::cout << "hehe" << std::endl;
#endif
return 0;
}

4 屬性

4.1 fallthrough

用于switch語句塊內(nèi),表示會(huì)執(zhí)行下一個(gè)case或default

如:

int main()
{
 int ok1, ok2;
 switch (0)
 {
  case 0:
  ok1 = 0;
  [[fallthrough]];
  case 1:
  ok2 = 1;
  [[fallthrough]];
 }
 return 0;
}

4.2 nodiscard

可用于類聲明、函數(shù)聲明、枚舉聲明中,表示函數(shù)的返回值沒有被接收,在編譯時(shí)會(huì)出現(xiàn)警告。

如:

[[nodiscard]] class A {}; //該屬性在這其實(shí)沒用
[[nodiscard]] enum class B {}; //該屬性在這其實(shí)沒用
class C {};
 
[[nodiscard]] int foo()
{ return 10; }
 
[[nodiscard]] A func1() { return A(); }
[[nodiscard]] B func2() { return B(); }
[[nodiscard]] C func3() { return C(); }
 
int main()
{
 foo();//warning: ignoring return value
 func1();//warning: ignoring return value
 func2();//warning: ignoring return value
 func3();//warning: ignoring return value
 return 0;
}

4.3 maybe_unused

可用于類、typedef、變量、非靜態(tài)數(shù)據(jù)成員、函數(shù)、枚舉或枚舉值中。用于抑制編譯器對沒用實(shí)體的警告。即加上該屬性后,對某一實(shí)體不會(huì)發(fā)出“沒有用”的警告。

用法例子:

[[maybe_unused]] class A {};
[[maybe_unused]] enum B {};
[[maybe_unused]] int C;
[[maybe_unused]] void fun();

結(jié)語

本次檢驗(yàn)C++17新特性使用了GCC編譯器,對于Clang的支持性方面沒有做出差異測試。若有問題,歡迎指出

到此這篇關(guān)于C++17新特性個(gè)人總結(jié)的文章就介紹到這了,更多相關(guān)C++17新特性內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/qq811299838/article/details/90371604

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 午夜亚洲视频 | 91一区二区在线观看 | 在线视频观看一区二区 | 亚洲精品一区二区三区大胸 | 在线a| 看黄在线观看 | 一级黄色在线免费观看 | 久久亚洲精品国产一区 | 亚洲一二区视频 | 久久国产亚洲视频 | 欧美一级做 | 国产精品久久久久久婷婷天堂 | 欧美一区二区黄 | 一区二区三区欧洲 | 国产女王女m视频vk 毛片免费在线视频 | 蜜桃成品人免费视频 | 黄色网址在线免费播放 | 久久久av亚洲男天堂 | av在线电影网| 99欧美视频 | 精品伊人 | 综合欧美一区二区三区 | 思思久而久而蕉人 | 久久综合九色综合久久久精品综合 | 精品亚洲在线 | 精品一区二区三区在线视频 | 一区二区三区欧美日韩 | 精品999久久久 | 成人午夜视频在线观看免费 | 国产精品久久久久久影院8一贰佰 | 欧美日韩亚洲成人 | 欧美一级黄色录像片 | 激情久久精品 | 日本中文字幕电影在线观看 | 亚洲va国产va | 亚洲第一色片 | 久久久精品视频国产 | 国产老师做www爽爽爽视频 | 国产噜噜噜噜久久久久久久久 | 久久久久久久久久综合 | 国产精品视频一区二区噜噜 |