C17 是 C 標準委員會於 2017 年制定的標準（ISOIEC 14882），接替 C14 標準，後被 C20 標準取代。 歷史 在 C 標準委員會制定此次的三年期標準之前，C17 標準的釋出日期是不確定的。在這段日期中，C17 草案（draft）也被稱為 C1z，正如 C11 草案名 C0x 或 C1x，C14 草案名 C1y。C17 標準於 2017 年 3 月完成國際標準草案（Draft International Standard DIS）階段，並於同年 12 月完成最終標準釋出。17 標準對 C 語法進行了加強，並對標準模板庫進行了些許修改，如給 algorithm 庫中演算法增加了執行策略 execution 以支援平行計算。 新功能 靜態斷言 static_assert 無需提供出錯資訊 移除 trigraphsIBM comment on preparing for a Trigraphadverse future in C17 IBM paper N4210 20141010 Authors Michael Wong Hubert Tong Rajan Bhakta Derek Inglis 具有模板形式的模板（template template）引數允許使用 typename（之前僅允許使用 class） stduncaught_exceptions 取代 stduncaught_exception 變長引數模板的 Folding 運算 容器存取操作表示方法的統一化（Uniform container access） 連續型迭代器（Contiguous Iterators） 新增特殊數學函式 引進 Library Fundamentals TS I 中的內容 類模板的模板引數推導 模板類建構函式能自動推導模板引數的型別 Class template argument deduction CTAD。例如允許以 pair 50 false 取代 pairdoublebool50 false template typename T float struct MyContainer T val MyContainer val MyContainer T val val val MyContainer c1 1 OK MyContainerint MyContainer c2 OK MyContainerfloat 任何指定變數或變數模板的初始化的宣告，其宣告的型別是類模板（可能是 cv 限定的）。如 stdpair p 2 45 deduces to stdpairint double p 2 45 new 表示式，如 templateclass Tstruct A A T T auto y new A 1 2 allocated type is Aint 用 auto 宣告非型別模板引數 依據 auto 的推到規則，在可允許型別的非型別模板引數情況下，可從實參型別推匯出模板引數： template auto seq struct my_integer_sequence Implementation here Explicitly pass type int as template argument auto seq stdinteger_sequenceint 0 1 2 Type is deduced to be int auto seq2 my_integer_sequence0 1 2 摺疊表示式 摺疊表示式在運算子上執行模板引數包的展開計算。 單元摺疊：形如 op e or e op 表示式，其中 op 是摺疊運算子，e 是未展開的模板引數包。 二元摺疊：形如 e1 op op e2 表示式， 其中 op 是摺疊運算子，e1 或 e2 是未展開的模板引數包。 template typename Args bool logicalAnd Args args Binary folding return true args bool b true bool b2 b logicalAnd b b2 true true template typename Args auto sum Args args Unary folding return args sum 10 20f 3 60 大括號初始化列表的新的自動推導規則 以前 auto x 3 將被推導為 stdinitializer_listint 現在推導為 int。 auto x1 1 2 3 error not a single element auto x2 1 2 3 x2 is stdinitializer_listint auto x3 3 x3 is int auto x4 30 x4 is double constexpr lambda auto identity int n constexpr return n static_assert identity 123 123 constexpr auto add int x int y auto L return x auto R return y return return L R static_assert add 1 2 3 constexpr int addOne int n return n return n 1 static_assert addOne 1 2 Lambda 函式中按值捕獲 this 指標 以前 this 指標在 lambda 函式只能按引用捕獲。現在 this 捕獲物件的副本，而 this C11 繼續捕獲引用。 struct MyObj int value 123 auto getValueCopy return this return value auto getValueRef return this return value MyObj mo auto valueCopy mogetValueCopy auto valueRef mogetValueRef movalue 321 valueCopy 123 valueRef 321 內聯變數 過去關鍵字 inline 可用於函式宣告，現在也可以用於變數宣告，表示函式或定義可定義（但內容必須完全相同）多次。這允許在標頭檔案中定義一個內聯變數。 內聯的函式或變數必須在編譯單元內可達（但不一定在訪問點之前） 在每個編譯單元中都是內聯宣告的 內聯變數必須是靜態儲存器（類靜態成員或名稱空間作用域變數），不能用於塊作用域變數或函式作用域變數。 struct S S id count S count int id static inline int count 0 declare and initialize count to 0 within the class 巢狀的名稱空間 如下： namespace A namespace B namespace C int i The code above can be written like this namespace ABC int i 結構化繫結 變數定義初始化時，允許形如 auto x y z expr，其中 expr 的 元組類似的物件 包括 stdtuple stdpair stdarray 等聚合結構。 using Coordinate stdpairint int Coordinate origin return Coordinate 0 0 const auto x y origin x 0 y 0 stdunordered_mapstdstring int mapping a 1 b 2 c 3 Destructure by reference for const auto key value mapping Do something with key and value 帶初始化的選擇語句 if 和 switch 語句允許如下的變數宣告和初始化： stdlock_guardstdmutex lk mx if vempty vpush_back val vs if stdlock_guardstdmutex lk mx vempty vpush_back val Foo gadget args switch auto s gadgetstatus case OK gadgetzip break case Bad throw BadFoo smessage vs switch Foo gadget args auto s gadgetstatus case OK gadgetzip break case Bad throw BadFoo smessage constexpr if 適用場景 1：簡化模版偏特化的寫法 template typename T constexpr bool isIntegral if constexpr stdis_integralTvalue return true else return false static_assert isIntegralint true static_assert isIntegralchar true static_assert isIntegraldouble false struct S static_assert isIntegralS false 適用場景 2：編寫變參模版函式 templateint N intNs int Sum if constexpr 0 sizeofNs return N else return NSumNs 使用場景 3：替代 enable_if。編寫模板函式時，經常要使用 enable_if 語句來進行靜態型別檢查，保證模板輸入的型別滿足某種要求 template typename T bool IsOdd T inputif constexpr stdis_integralTvalue return static_castboolinput 2 utf8 字面量 如下： char x u8x 列舉型別變數直接用大括號初始化 enum byte unsigned char byte b 0 OK byte c 1 ERROR byte d byte 1 OK byte e byte 256 ERROR fallthrough nodiscard maybe_unused 特性 C17 引入了 3 個特性（attribute） fallthrough nodiscard maybe_unused fallthrough 指示編譯器直通一個 switch 語句： switch n case 1 fallthrough case 2 break nodiscard 引發一個警告，當具有該特性的函式或類的返回值被忽略： nodiscard bool do_something return is_success true for success false for failure do_something warning ignoring return value of bool do_something declared with attribute nodiscard Only issues a warning when error_info is returned by value struct nodiscard error_info error_info do_something error_info ei return ei do_something warning ignoring returned value of type error_info declared with attribute nodiscard maybe_unused 告訴編譯器變數或引數可能未被使用： void my_callback stdstring msg maybe_unused bool error Dont care if msg is an error message just log it log msg __has_include 運算子 __has_include 運算子用在 if 和 elif 表示式，以檢查是否一個頭檔案或原始檔可否包含。 下例有兩個相同作用的標頭檔案，如果主檔案不能包含， 就使用 backupexperimental 標頭檔案： ifdef __has_include if __has_include optional include optional define have_optional 1 elif __has_include experimentaloptional include experimentaloptional define have_optional 1 define experimental_optional else define have_optional 0 endif endif 也可以用在不同位置、不同名字但具有相同地位的標頭檔案的包含： ifdef __has_include if __has_include OpenGLglh include OpenGLglh include OpenGLgluh elif __has_include GLglh include GLglh include GLgluh else error No suitable OpenGL headers found endif endif stdvariant stdvariant 模板類實現了型別安全的 union stdvariantint double v 12 stdgetintv 12 stdget0v 12 v 120 stdgetdoublev 120 stdget1v 120 stdoptional stdoptional 類模板可能包含一個值或者可能不包含值： stdoptionalstdstring create bool b if b return Godzilla else return 或者 return stdnullopt create falsehas_value 返回 true 或 false create false 返回值；如果無值，則返回 T create falsevalue_or empty empty create truevalue Godzilla optionalreturning factory functions are usable as conditions of while and if if auto str create true stdany stdany 模板類是型別安全的包含任何型別的值： stdany x 5 xhas_value true stdany_castintx 5 stdany_castintx 10 stdany_castintx 10 stdstring_view stdstring_view 類是不擁有字串的情況可以讀取其值： Regular strings stdstring_view cppstr foo Wide strings stdwstring_view wcstr_v Lbaz Character arrays char array 3 b a r stdstring_view array_v array stdsize array stdstring str trim me stdstring_view v str vremove_prefix stdmin vfind_first_not_of vsize str trim me v trim me stdstring_view 不提供 c_str 成員函式。 stdinvoke stdinvoke 用於呼叫 可呼叫物件。 template typename Callable class Proxy Callable c public Proxy Callable c c c template class Args decltype auto operator Args args return stdinvoke c stdforwardArgsargs auto add int x int y return x y Proxydecltype add p add p 1 2 3 stdapply stdapply 把 stdtuple 引數應用於可呼叫物件： auto add int x int y return x y stdapply add stdmake_tuple 1 2 3 stdfilesystem stdfilesystem 可操作檔案、目錄、路徑： const auto bigFilePath bigFileToCopy if stdfilesystemexists bigFilePath const auto bigFileSize stdfilesystemfile_size bigFilePath stdfilesystempath tmpPath tmp if stdfilesystemspace tmpPathavailable bigFileSize stdfilesystemcreate_directory tmpPathappend example stdfilesystemcopy_file bigFilePath tmpPathappend newFile stdbyte stdbyte 型別既不是字元型別，也不是算術型別，實際上是列舉型別： stdbyte a 0 stdbyte b 0xFF int i stdto_integerintb 0xFF stdbyte c a b int j stdto_integerintc 0 maps 和 sets 上更有效率地移動節點 零開銷的節點操作： Moving elements from one map to another stdmapint string src 1 one 2 two 3 buckle my shoe stdmapint string dst 3 three dstinsert srcextract srcfind 1 Cheap remove and insert of 1 one from src to dst dstinsert srcextract 2 Cheap remove and insert of 2 two from src to dst dst 1 one 2 two 3 three Inserting an entire set stdsetint src 1 3 5 stdsetint dst 2 4 5 dstmerge src src 5 dst 1 2 3 4 5 Inserting elements which outlive the container auto elementFactory stdset s semplace return sextract sbegin s2insert elementFactory Changing the key of a map element stdmapint string m 1 one 2 two 3 three auto e mextract 2 ekey 4 minsert stdmove e m 1 one 3 three 4 two 並行演算法 許多 STL 演算法，如 copy find 和 sort，支援並行執行政策：seq par par_unseq unseq 分別表示 sequentially parallel parallel unsequenced unsequenced stdvectorint longVector Find element using parallel execution policy auto result1 stdfind stdexecutionpar stdbegin longVector stdend longVector 2 Sort elements using sequential execution policy auto result2 stdsort stdexecutionseq stdbegin longVector stdend longVector 注釋 另見 C C14 C11 categoryC Category 程式語言標準