青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

專職C++

不能停止的腳步

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  163 Posts :: 7 Stories :: 135 Comments :: 0 Trackbacks

常用鏈接

留言簿(28)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

原文:http://geek.csdn.net/news/detail/228484

C++17標準在2017上半年已經討論確定,正在形成ISO標準文檔,今年晚些時候會正式發(fā)布。本文將介紹最新標準中值得開發(fā)者關注的新特新和基本用法。

總的來說C++17相比C++11的新特性來說新特性不算多,做了一些小幅改進。C++17增加了數十項新特性,值得關注的特性大概有下面這些:

  • constexpr if
  • constexpr lambda
  • fold expression
  • void_t
  • structured binding
  • std::apply, std::invoke
  • string_view
  • parallel STL
  • inline variable

剩下的有一些來自于boost庫,比如variant,any、optional和filesystem等特性,string_view其實在boost里也有。還有一些是語法糖,比如if init、deduction guide、guaranteed copy Elision、template、nested namespace、single param static_assert等特性。我接下來會介紹C++17主要的一些特性,介紹它們的基本用法和作用,讓讀者對C++17的新特性有一個基本的了解。

fold expression

C++11增加了一個新特性可變模版參數(variadic template),它可以接受任意個模版參數在參數包中,參數包是三個點…,它不能直接展開,需要通過一些特殊的方法才能展開,導致在使用的時候有點難度。現在C++17解決了這個問題,讓參數包的展開變得容易了,Fold expression就是方便展開參數包的。

fold expression的語義 
fold expression有4種語義:

  1. unary right fold (pack op …)
  2. unary left fold (… op pack)
  3. binary right fold (pack op … op init)
  4. binary left fold (init op … op pack)

其中pack代表變參,比如args,op代表操作符,fold expression支持32種操作符:

+ - * / % ^ & | = < > << >> += -= *= /= %= ^= &= |= <<= >>= == != <= >= && || , .* ->*

unary right fold的含義

fold (E op …) 意味著 E1 op (… op (EN-1 op EN)).

顧名思義,從右邊開始fold,看它是left fold還是right fold我們可以根據參數包…所在的位置來判斷,當參數包…在操作符右邊的時候就是right fold,在左邊的時候就是left fold。我們來看一個具體的例子:

template<typename... Args> auto add_val(Args&&... args) {     return (args +  ...); }  auto t = add_val(1,2,3,4); //10 

right fold的過程是這樣的:(1+(2+(3+4))),從右邊開始fold。

unary left fold的含義

fold (… op E) 意味著 ((E1 op E2) op …) op EN。

對于+這種滿足交換律的操作符來說left fold和right fold是一樣的,比如上面的例子你也可以寫成left fold。

template<typename... Args> auto add_val(Args&&... args) {     return (... + args); }  auto t = add_val(1,2,3,4); //10 

對于不滿足交換律的操作符來說就要注意了,比如減法。

template<typename... Args> auto sub_val_right(Args&&... args) {     return (args - ...); }   template<typename... Args> auto sub_val_left(Args&&... args) {     return (... - args); }  auto t = sub_val_right(2,3,4); //(2-(3-4)) = 3 auto t1 = sub_val_left(2,3,4); //((2-3)-4) = -5 

這次right fold和left fold的結果就不一樣。

binary fold的含義

Binary right fold (E op … op I) 意味著 E1 op (… op (EN-1 op (EN op I)))。

Binary left fold (I op … op E) 意味著 (((I op E1) op E2) op …) op E2。

其中E代表變參,比如args,op代表操作符,I代表一個初始變量。

二元fold的語義和一元fold的語義是相同的,看一個二元操作符的例子:

template<typename... Args> auto sub_one_left(Args&&... args) {     return (1 - ... - args); }  template<typename... Args> auto sub_one_right(Args&&... args) {     return (args - ... - 1); }  auto t = sub_one_left(2,3,4);// (((1-2)-3)-4) = -8 auto t1 = sub_one_right(2,3,4);//(2-(3-(4-1))) = 2 

相信通過這個例子大家應該對C++17的fold expression有了基本的了解。

comma fold

在C++17之前,我們經常使用逗號表達式和std::initializer_list來將變參一個個傳入一個函數。比如像下面這個例子:

template<typename T> void print_arg(T t) {     std::cout << t << std::endl; }  template<typename... Args> void print2(Args... args) {     //int a[] = { (printarg(args), 0)... };     std::initializer_list<int>{(print_arg(args), 0)...}; } 

這種寫法比較繁瑣,用fold expression就會變得很簡單了。

template<typename... Args> void print3(Args... args) {     (print_arg(args), ...); } 

這是right fold,你也可以寫成left fold,對于comma來說兩種寫法是一樣的,參數都是從左至右傳入print_arg函數。

template<typename... Args> void print3(Args... args) {     (..., print_arg(args)); } 

你也可以通過binary fold這樣寫:

template<typename ...Args> void printer(Args&&... args) {     (std::cout << ... << args) << '\n'; } 

也許你會覺得能寫成這樣:

template<typename ...Args> void printer(Args&&... args) {     (std::cout << args << ...) << '\n'; } 

但這樣寫是不合法的,根據binary fold的語法,參數包…必須在操作符中間,因此上面的這種寫法不符合語法要求。

借助comma fold我們可以簡化代碼,假如我們希望實現tuple的for_each算法,像這樣:

for_each(std::make_tuple(2.5, 10, 'a'),[](auto e) { std::cout << e<< '\n'; }); 

這個for_each將會遍歷tuple的元素并打印出來。在C++17之前我們如果要實現這個算法的話,需要借助逗號表達式和std::initializer_list來實現,類似于這樣:

template <typename... Args, typename Func, std::size_t... Idx> void for_each(const std::tuple& t, Func&& f, std::index_sequence<Idx...>) {     (void)std::initializer_list<int> { (f(std::get<Idx>(t)), void(), 0)...}; } 

這樣寫比較繁瑣不直觀,現在借助fold expression我們可以簡化代碼了。

template <typename... Args, typename Func, std::size_t... Idx> void for_each(const std::tuple<Args...>& t, Func&& f, std::index_sequence<Idx...>) {     (f(std::get<Idx>(t)), ...); } 

借助coma fold我們可以寫很簡潔的代碼了。

constexpr if

constexpr標記一個表達式或一個函數的返回結果是編譯期常量,它保證函數會在編譯期執(zhí)行。相比模版來說,實現編譯期循環(huán)或遞歸,C++17中的constexpr if會讓代碼變得更簡潔易懂。比如實現一個編譯期整數加法:

template<int N> constexpr int sum() {     return N; }  template <int N, int N2, int... Ns> constexpr int sum() {     return N + sum<N2, Ns...>(); } 

C++17之前你可能需要像上面這樣寫,但是現在你可以寫更簡潔的代碼了。

template <int N, int... Ns> constexpr auto sum17() {     if constexpr (sizeof...(Ns) == 0)         return N;     else         return N + sum17<Ns...>(); } 

當然,你也可以用C++17的fold expression:

template<typename ...Args> constexpr int sum(Args... args) {     return (0 + ... + args); } 

constexpr還可以用來消除enable_if了,對于討厭寫一長串enable_if的人來說會非常開心。比如我需要根據類型來選擇函數的時候:

template<typename T> std::enable_if_t<std::is_integral<T>::value, std::string> to_str(T t) {     return std::to_string(t); }  template<typename T> std::enable_if_t<!std::is_integral<T>::value, std::string> to_str(T t) {     return t; } 

經常不得不分開幾個函數來寫,還需要寫長長的enable_if,比較繁瑣,通過if constexpr可以消除enable_if了。

template<typename T> auto to_str17(T t) {     if constexpr(std::is_integral<T>::value)         return std::to_string(t);     else         return t; } 

constexpr if讓C++的模版具備if-else if-else功能了,是不是很酷,C++程序員的好日子來了。

不過需要注意的是下面這種寫法是有問題的。

template<typename T> auto to_str17(T t) {     if constexpr(std::is_integral<T>::value)         return std::to_string(t);          return t; } 

這個代碼把else去掉了,當輸入如果是非數字類型時代碼可以編譯過,以為if constexpr在模版實例化的時候會丟棄不滿足條件的部分,因此函數體中的前兩行代碼將失效,只有最后一句有效。當輸入的為數字的時候就會產生編譯錯誤了,因為if constexpr滿足條件了,這時候就會有兩個return了,就會導致編譯錯誤。

constexpr if還可以用來替換#ifdef宏,看下面的例子

enum class OS { Linux, Mac, Windows };  //Translate the macros to C++ at a single point in the application #ifdef __linux__ constexpr OS the_os = OS::Linux; #elif __APPLE__ constexpr OS the_os = OS::Mac; #elif __WIN32 constexpr OS the_os = OS::Windows; #endif  void do_something() {      //do something general       if constexpr (the_os == OS::Linux) {          //do something Linuxy      }      else if constexpr (the_os == OS::Mac) {          //do something Appley      }      else if constexpr (the_os == OS::Windows) {          //do something Windowsy      }       //do something general } //備注:這個例子摘自https://blog.tartanllama.xyz/c++/2016/12/12/if-constexpr/ 

代碼變得更清爽了,再也不需要像以前一樣寫#ifdef那樣難看的代碼塊了。

constexpr lambda

constexpr lambda其實很簡單,它的意思就是可以在constexpr 函數中用lambda表達式了,這在C++17之前是不允許的。這樣使用constexpr函數和普通函數沒多大區(qū)別了,使用起來非常舒服。下面是constexpr lambda的例子:

template <typename I> constexpr auto func(I i) {   //use a lambda in constexpr context   return [i](auto j){ return i + j; };  } 

constexpr if和constexpr lambda是C++17提供的非常棒的特性,enjoy it.

string_view

string_view的基本用法

C++17中的string_view是一個char數據的視圖或者說引用,它并不擁有該數據,是為了避免拷貝,因此使用string_view可以用來做性能優(yōu)化。你應該用string_view來代替const char和const string了。string_view的方法和string類似,用法很簡單:

const char* data = "test"; std::string_view str1(data, 4); std::cout<<str1.length()<<'\n'; //4 if(data==str1)     std::cout<<"ok"<<'\n';  const std::string str2 = "test"; std::string_view str3(str2, str2.size()); 

構造string_view的時候用char*和長度來構造,這個長度可以自由確定,它表示string_view希望引用的字符串的長度。因為它只是引用其他字符串,所以它不會分配內存,不會像string那樣容易產生臨時變量。我們通過一個測試程序來看看string_view如何來幫我們優(yōu)化性能的。

using namespace std::literals;  constexpr auto s = "it is a test"sv; auto str = "it is a test"s;  constexpr int LEN = 1000000; boost::timer t; for (int i = 0; i < LEN; ++i) {     constexpr auto s1 = s.substr(3); } std::cout<<t.elapsed()<<'\n'; t.restart(); for (int i = 0; i < LEN; ++i) {     auto s2 = str.substr(3); } std::cout<<t.elapsed()<<'\n';  //output 0.004197 0.231505 

我們可以通過字面量””sv來初始化string_view。string_view的substr和string的substr相比,快了50多倍,根本原因是它不會分配內存。

string_view的生命周期

由于string_vew并不擁有鎖引用的字符串,所以它也不會去關注被引用字符串的生命周期,用戶在使用的時候需要注意,不要將一個臨時變量給一個string_view,那樣會導致string_view引用的內容也失效。

std::string_view str_v; {     std::string temp = "test";     str_v = {temp}; } 

這樣的代碼是有問題的,因為出了作用域之后,string_view引用的內容已經失效了。

總結

本文介紹了C++17的fold expression、constexpr if、constexpr lambda和string_view。fold expression為了簡化可變模板參數的展開,讓可以模板參數的使用變得更簡單直觀;constexpr if讓模板具備if-else功能,非常強大。它也避免了寫冗長的enable_if代碼,讓代碼變得簡潔易懂了;string_view則是用來做性能優(yōu)化的,應該用它來代替const char*和const string。

這些特性對之前的C++14和C++11做了改進和增強,非常酷,歡迎訂閱《程序員》,后續(xù)系列文章會接著介紹其他C++17中值得關注的新特性。

posted on 2017-07-28 13:25 冬瓜 閱讀(1909) 評論(1)  編輯 收藏 引用 所屬分類: 轉貼

Feedback

# re: [轉貼]C++17中那些值得關注的特性(上) 2017-07-31 17:44 Chipset
一堆學術派閑的蛋疼總搞語法,沒有一點實用價值。
就不能加點庫嗎?文件系統,通信,圖形...  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久噜噜噜久久久| 日韩一二三区视频| 麻豆精品一区二区综合av| 久久久亚洲国产天美传媒修理工 | 亚洲视频欧美在线| 亚洲精品一二区| 中日韩男男gay无套| 一区二区欧美国产| 亚洲自拍啪啪| 久久国产夜色精品鲁鲁99| 久久精品夜夜夜夜久久| 999亚洲国产精| 亚洲精品美女在线观看| 欧美成人精品1314www| 欧美大色视频| 亚洲国产欧美久久| 狼人社综合社区| 女同性一区二区三区人了人一| 美女视频黄a大片欧美| 亚洲国产精品一区二区久| 99日韩精品| 久久久欧美精品| 欧美精品激情| 国产色产综合色产在线视频| 亚洲成色999久久网站| 一区二区三区成人| 欧美在线观看一区二区| 亚洲国产精品成人综合| 亚洲女与黑人做爰| 欧美成人精品影院| 国产精品永久免费| av成人动漫| 欧美成人国产一区二区| 亚洲在线视频网站| 欧美激情第二页| 国产一区久久| 亚洲欧美日韩一区二区三区在线| 久久午夜视频| 亚洲视频狠狠| 欧美日韩国产另类不卡| 在线成人av网站| 久久国产精彩视频| 亚洲视频在线观看网站| 欧美激情精品久久久久久变态 | 国内精品视频666| 一区二区国产日产| 另类人畜视频在线| 午夜国产精品视频| 国产精品久在线观看| 一区二区免费看| 亚洲国产清纯| 麻豆精品网站| 在线日韩中文字幕| 久久美女性网| 欧美一区二区视频观看视频| 国产精品萝li| 午夜亚洲福利在线老司机| 99国产精品99久久久久久| 老司机午夜免费精品视频| 红桃视频一区| 久久综合图片| 久久精品一区二区国产| 精品成人a区在线观看| 久久婷婷国产综合国色天香| 亚洲男人第一网站| 国产欧美一区视频| 久久精品毛片| 亚洲欧美日韩国产另类专区| 在线一区二区三区四区五区| 欧美日韩国产成人在线观看| avtt综合网| 亚洲美女精品一区| 欧美日韩综合在线| 亚洲无吗在线| 欧美一级播放| 黄色亚洲大片免费在线观看| 免费在线观看成人av| 蜜桃精品久久久久久久免费影院| 亚洲国产欧美一区二区三区丁香婷| 久久久久欧美| 欧美成人按摩| 亚洲一区三区电影在线观看| 午夜国产精品影院在线观看 | 欧美在线一二三| 国内精品久久久久久| 欧美丰满少妇xxxbbb| 欧美另类videos死尸| 亚洲综合国产激情另类一区| 欧美怡红院视频| 亚洲激情视频网站| 一区二区三区精品在线| 国产日韩精品久久| 亚洲电影免费| 欧美日韩亚洲天堂| 久久精品一区二区三区中文字幕| 玖玖在线精品| 午夜精品一区二区三区在线| 久久性天堂网| 亚洲永久免费av| 久久久久一区二区| 亚洲婷婷在线| 久久久久久**毛片大全| 亚洲天堂激情| 久久综合国产精品| 亚洲在线电影| 一区二区激情视频| 久久精品麻豆| 国产精品日本一区二区| 久久综合中文色婷婷| 欧美丰满少妇xxxbbb| 午夜精品网站| 欧美激情综合亚洲一二区| 久久国产精品久久久| 欧美成人精品1314www| 久久国产精品第一页| 欧美日韩国产限制| 欧美成人一区二区三区在线观看| 欧美天天影院| 亚洲精品一二三| 亚洲国产第一| 久久精品人人做人人综合| 亚洲一区二区动漫| 麻豆精品视频在线| 久久免费国产| 国产欧美一区二区三区在线老狼| 日韩午夜电影| 亚洲人在线视频| 99视频精品全国免费| 日韩天堂av| 久久久99精品免费观看不卡| 午夜在线视频观看日韩17c| 欧美韩日一区| 欧美风情在线观看| 激情亚洲网站| 欧美一区二区三区在线观看 | 国产精品色婷婷久久58| 欧美成人午夜剧场免费观看| 欧美激情一区二区三区在线视频| 日韩午夜电影在线观看| 久久久久久伊人| 久久久久久久波多野高潮日日 | 最近中文字幕mv在线一区二区三区四区| 国产精品一区二区三区久久久| 99精品国产在热久久婷婷| 日韩小视频在线观看专区| 欧美成人精品一区二区| 亚洲国产成人精品久久| 在线观看一区二区精品视频| 欧美在线观看视频一区二区三区| 久久国产精品第一页| 国内一区二区在线视频观看| 久久久久久久高潮| 亚洲大片av| 亚洲视频二区| 国产精品最新自拍| 久久久久久97三级| 亚洲国产免费| 亚洲淫片在线视频| 国产精品亚洲综合一区在线观看| 午夜日本精品| 欧美大片一区二区三区| 日韩视频免费在线| 国产精品欧美日韩| 久久久久高清| 亚洲精品一区二区在线| 欧美亚洲综合在线| 亚洲成人在线免费| 欧美日韩国产成人| 午夜在线视频观看日韩17c| 巨乳诱惑日韩免费av| 亚洲精品久久久久久久久久久| 欧美视频一区在线观看| 久久久精品国产免大香伊| 亚洲欧洲午夜| 久久精品综合一区| 99re8这里有精品热视频免费 | 一本综合精品| 国产精品三区www17con| 蜜臀99久久精品久久久久久软件| 亚洲最黄网站| 另类酷文…触手系列精品集v1小说| 一本色道久久加勒比精品| 狠狠久久五月精品中文字幕| 欧美极品色图| 久久久精品午夜少妇| 中国亚洲黄色| 亚洲人成毛片在线播放| 久久香蕉国产线看观看av| 亚洲一级特黄| 欧美日韩岛国| 久久久久国产精品麻豆ai换脸| 亚洲日韩成人| 久久一区中文字幕| 午夜电影亚洲| 一区二区三区欧美在线| 亚洲国产天堂久久综合网| 国产日韩欧美综合在线| 欧美日韩视频一区二区三区| 噜噜噜噜噜久久久久久91| 欧美亚洲视频|