C++17部分特性整理

C++17部分特性整理

1、使 static_assert 的文本信息可选

  • 简化和 static_assert的使用,c++17起,消息 可选
static_assert ( 布尔常量表达式 , 消息 )   (C++11 起)  
static_assert ( 布尔常量表达式 )   (C++17 起)

2、删除 trigraphs

  • 删除三元转移字符
  • 最初因为iso646的标准,部分国家打不出# ~ ^ 之类的字符,使用??加一个字符的方式替代,c++11中不建议使用trigraphs,c++17中被弃用
Trigraph Equivalent
??= #
??/ \
??' ^
??( [
??) ]
??! ` `
??< {
??> }
??- ~

3、在模板参数中允许使用 typename(作为替代类)

template<typename T> class my_array {};

// 两个类型模板形参和一个模板模板形参:
template<typename K, typename V, template<typename> typename C = my_array>
class Map
{
    C<K> key;
    C<V> value;
};

4、braced-init-list自动推导的新规则

  • 采用大括号的形式初始化auto变量,可以自动完成类型的推导
  • 规则braced-init-list 左侧只能是单个元素
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int> 【initializer_list用于表示特定类型值的数组】
auto x2 = { 1, 2.0 }; // error: cannot deduce element type,会对右侧常量进行类型检查
auto x3{ 1, 2 }; // error: not a single element
auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int>
auto x5{ 3 }; // decltype(x5) is int
  • std::initializer_list的简单介绍【列表初始化】

    std::vector<int>a{1,2,3,4,5};
    std::vector<int>a = {1,2,3,4,5};
    //vecotr可以使用列表进行初始化,因为{1,2,3,4,5}被推导为std::initializer_list<int>类型,vector的构造函数对std::initializer_list<int>类型进行特化和对赋值运算符的重载进行了特化。
    
    

    [图片上传失败...(image-bff33a-1584675555477)]

5、嵌套命名空间

  • 嵌套命名空间定义:namespace A::B::C { ... } 等价于 namespace A { namespace B { namespace C { ... } } }。
  • namespace A::B::inline C { ... } 等价于 namespace A::B { inline namespace C { ... } }。(c++20)inline 可出现于除首个以外的每个命名空间名之前

6、允许命名空间和枚举器的属性

1、格式

枚举格式:

enumerator: identifier attribute-specifier-seqopt

作用域格式:

  • original-namespace-definition:
    inlineopt namespace attribute-specifier-seqopt identifier { namespace-body }
  • extension-namespace-definition:
    inlineopt namespace attribute-specifier-seqopt original-namespace-name { namespace-body }
  • unnamed-namespace-definition:
    inlineopt namespace attribute-specifier-seqopt { namespace-body }

2、属性格式

[[attr]] [[attr1, attr2, attr3(args)]]

3、语法

  • [[ 属性列表 ]] (c++11)
  • [[ using 属性命名空间 :属性列表]] (c++17)

4、属性实例

(未找到有关namesapce和enum相关的实例,以函数属性列表的使用举例)

[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int f(); // 声明 f 带四个属性
 
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // 同上,但使用含有四个属性的单个属性说明符
 
// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // 属性可出现于多个说明符中
 
int f() { return 0; }
 
int main() {}

7、新的标准属性:

[[fallthrough]]:

  • 仅可应用到空语句以创建直落语句(fallthrough statement):[[fallthrough]];。

  • 直落语句仅可用于 switch 语句中,其中待执行的下个语句是该 switch 语句的带 case 或 default 标号的语句。

  • 指示从前一标号直落是有意的,而在发生直落时给出警告的编译器不应诊断它

    void f(int n) {
      void g(), h(), i();
      switch (n) {
        case 1:
        case 2:
          g();
         [[fallthrough]];
        case 3: // 直落时不警告
          h();
        case 4: // 编译器可在发生直落时警告【实际运行结果并未发生警告】
          if(n < 3) {
              i();
              [[fallthrough]]; // OK
          }
          else {
              return;
          }
        case 5:
          [[fallthrough]]; // 非良构,无后继的 case 或 default 标号
      }
    }
    

[[nodiscard]]

  • 出现在函数声明、枚举声明或类声明中
  • 若从并非转型到 void 的弃值表达式中,调用声明为 nodiscard 的函数,或调用按值返回声明为 nodiscard 的枚举或类的函数,则鼓励编译器发布警告。
struct [[nodiscard]] error_info { };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
   enable_missile_safety_mode(); // 编译器可在舍弃 nodiscard 值时发布警告
   launch_missiles();
}
error_info& foo();
void f1() {
    foo(); // 并非按值返回 nodiscard 类型,无警告
}

[[maybe_unused]]

  • 抑制针对未使用实体的警,此属性可出现在下列实体的声明中:
  • 若编译器针对未使用实体发布警告,则对于任何声明为 maybe_unused 的实体抑制该警告。
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2)
{
   [[maybe_unused]] bool b = thing1 && thing2;
   assert(b); // 发行模式中,assert 在编译中被去掉,因而未使用 b
              // 无警告,因为它被声明为 [[maybe_unused]]
} // 未使用参数 thing1 与 thing2,无警告

9、允许所有非类型模板实参的常量求值

  • 附:实例
//队列某个元素或者非静态数据成员的地址,对于非类型模板参数是不合法的;
template<int* p> class X { };

int a[10];
struct S { int m; static int s; } s;

X<&a[2]> x3; // error: address of array element
X<&s.m> x4;  // error: address of non-static member
X<&s.s> x5;  // error: &S::s must be used OK: address of static member
X<&S::s> x6; // OK: address of static member

10、折叠表达式及在可变长参数模板中的使用

折叠表达式

格式

  • 一元左折叠(pack op ...)
  • 一元右折叠(... op pack)
  • 二元右折叠(pack op ... op I)
  • 二元左折叠(I op ... op pack)

展开

  • 一元左折叠展开:((E1 op E2) op ...) op EN
  • 一元右折叠展开:E1 op (... op (EN-1 op EN))
  • 二元右折叠展开:E1 op (... op (EN-1 op (EN op I)))
  • 二元左折叠展开:(((I op E1) op E2) op ...) op EN

注意

  • 若用作 init 或 pack 的表达式在顶层优先级低于转型,则它可以加括号:
template<typename ...Args>
int sum(Args&&... args) {
//    return (args + ... + 1 * 2); // 错误:优先级低于转型的运算符
    return (args + ... + (1 * 2)); // OK
}
  • 二元折叠表达式两边的操作数只能有一个未展开的的参数包
template<typename... Args>
  bool f(Args... args) { 
    return (true + ... + args); // OK
  } 

template<typename... Args>
  bool f(Args... args) { 
    return (args && ... && args); // error: both operands contain unexpanded parameter packs
  }

变长参数模板参数解包方法

之前解包方法:

# include <iostream >
template < typename T0 >
void printf (T0 value ) {
    std :: cout << value << std :: endl ;
}
template < typename T, typename ... Args >
void printf (T value , Args ... args ) {
    std :: cout << value << std :: endl ;
    printf ( args ...) ;
}
int main () {
    printf (1, 2, "123 ", 1.1) ;
    return 0;
}

基于constexpr的解包方法[c++17]

template < typename T0, typename ... T>
void magic(T0 t0, T... t) {
    std::cout << t0 << std::endl;
    if constexpr (sizeof ...(t) > 0) magic(t ...);
}

11、if constexpr关键字的使用

  • C++11 引入了constexpr 关键字,它将表达式或函数编译为常量;

  • C++17 将constexpr 这个关键字引入到if 语句中,允许在代码中声明常量,把这一特性引入到条件判断中去,让代码在编译时就完成分支判断

    template < typename T>
    auto print_type_info ( const T& t) {
      if constexpr (std :: is_integral <T >:: value ) {
          return t + 1;
      } 
        else {
          return t + 0.001; 
        }
    }
    int main () {
      std :: cout << print_type_info (5) << std :: endl ;
      std :: cout << print_type_info (3.14) << std :: endl ;
    }
    

    编译时展现形式:

    int print_type_info ( const int & t) {
      return t + 1;
    }
    double print_type_info ( const double & t) {
      return t + 0.001;
    }
    

12、结构化绑定声明

1、格式

  • attr(可选) cv-auto ref-运算符(可选) [ 标识符列表 ] = 表达式 ;
  • attr(可选) cv-auto ref-运算符(可选) [ 标识符列表 ] {表达式 };
  • attr(可选) cv-auto ref-运算符(可选) [ 标识符列表 ] (表达式 );
名称 解释
attr 任意数量的属性的序列
cv-auto 可有 cv 限定的 auto 类型说明符
ref-运算符 &&& 之一
标识符列表 此声明所引入的各标识符的逗号分隔的列表
表达式 顶层没有逗号运算符的表达式(文法上为赋值表达式),且具有数组或非联合类之一的类型。

2、绑定情况

2.1绑定到数组

int a[2] = {1,2};
 
auto [x,y] = a; // 创建 e[2],复制 a 到 e,然后 x 指代 e[0],y 指代 e[1]
auto& [xr, yr] = a; // xr 指代 a[0],yr 指代 a[1]

2.2绑定到元组式类型

float x{};
char  y{};
int   z{};
 
std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
// a 指名指代 x 的结构化绑定;decltype(a) 为 float&
// b 指名指代 y 的结构化绑定;decltype(b) 为 char&&
// c 指名指代 tpl 的第 3 元素的结构化绑定;decltype(c) 为 const int

2.3绑定到数组成员

struct S {
    int x1 : 2;
    volatile double y1;
};
S f();
 
auto [x, y] = f(); // x 是标识 2 位位域的 int 左值
                   // y 是 volatile double 左值
//根据测试结果 auto [x, y]前不能加cv操作符,否则编译不过:由于tupule_size无法识别

3、注意示项

1、标志符的数量必须等于数组元素或元组元素或者结构体中非静态数据成员的数量;

13、if 和 switch 语句中的变量初始化

  • 在if和switch中可以完成初始化,

    • if ( init-statement <u>opt</u> condition ) statement
    • if ( init-statement <u>opt</u> condition ) statement else statement
    • switch ( init-statement <u>opt</u> condition ) statement

表达式展开格式如下:

  • if ( init-statement condition ) statement 展开格式如下:

{

init-statement

​ if ( condition ) statement

}

  • if ( init-statement condition ) statement else *statemen 展开格式如下:

{

init-statement

​ if ( condition ) statement else statement

}

  • switch ( init-statement condition ) statement 展开格式如下:

{

*init-statement*   

​ switch ( condition ) statement

}

实例

实例1

before

status_code foo() {  
    {     
        status_code c = bar();    
        if (c != SUCCESS) {      
            return c;     
        }   
    }  
    // ... 
}

after

status_code foo() {  
    if (status_code c = bar();c != SUCCESS) {      
        return c;     
    } 
    // ... 
}

实例2

before

void safe_init() { 
    {    
        std::lock_guard<std::mutex> lk(mx_);
        if (v.empty()){       
            v.push_back(kInitialValue);    
        }  
    }  
    // ... 
}

after

void safe_init() { 
    if (std::lock_guard<std::mutex> lk(mx_);v.empty()){       
            v.push_back(kInitialValue);    
     }   
    // ... 
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • (三)文学类文本阅读(本题共3小题,15分) 阅读下面的文字,完成7~9 题。 秋唱 ...
    傲气冲天925阅读 1,390评论 0 0
  • 误会了,在此特别登报声明!居然要登报了?有这么声势浩大的事吗?值得你如此大动干戈,也不怕引起人家笑话,当然有。因为...
    昭昭_21e3阅读 229评论 0 0
  • 论文纸片盒子 03FRACTURE FLOW RATE ESTIMATION USING MACHINE LEAR...
    亻令仃忝鉂阅读 630评论 0 0
  • 继承extends 单一继承,只能有一个父类 方法重写 返回值类型,方法名,参数类型,顺序,个数都要与父类相同。访...
    ssss2阅读 192评论 0 0
  • 什么样的女子,才可以活成岁月深处的那一抹嫣红,有一个自给自足的小宇宙,任凭时光流转,不倾,不颓,不必依然装扮粉嫩,...
    宋西坡阅读 245评论 5 7