C++14是C++的現(xiàn)行標(biāo)準(zhǔn)的非正式名稱,正式名稱為"International Standard ISO/IEC 14882:2014(E) PRogramming Language C++"。C++14旨在作為C++11的一個(gè)小擴(kuò)展,主要提供漏洞修復(fù)和小的改進(jìn)。C++14標(biāo)準(zhǔn)的委員會(huì)草案(Committee Draft)N3690于2013年5月15日發(fā)表。[1]工作草案(Working Draft)N3936已于2014年3月2日完成。最終的投票期結(jié)束于2014年8月15日,結(jié)果(一致通過)已于8月18日公布。[2]
以下為在C++14中被加入語言核心的特性。
在C++11中,lambda函數(shù)的形式參數(shù)需要被聲明為具體的類型。C++14放寬了這一要求,允許lambda函數(shù)的形式參數(shù)聲明中使用類型說明符auto。[3]
auto lambda = [](auto x, auto y) {return x + y;}泛型lambda函數(shù)遵循模板參數(shù)推導(dǎo)的規(guī)則。以上代碼的作用與下面的代碼相同:[4]
struct unnamed_lambda{ template<typename T, typename U> auto Operator()(T x, U y) const {return x + y;}};auto lambda = unnamed_lambda{};Lambda捕獲部分中使用表達(dá)式[編輯]
C++11的lambda函數(shù)通過值拷貝(by copy)或引用(by reference)捕獲(capture)已在外層作用域聲明的變量。這意味著lambda捕獲的變量不可以是move-only的類型。[5] C++14允許lambda成員用任意的被捕獲表達(dá)式初始化。這既允許了capture by value-move,也允許了任意聲明lambda的成員,而不需要外層作用域有一個(gè)具有相應(yīng)名字的變量。[6]這稱為廣義捕獲(Generalized capture)。[7]即在捕獲子句(capture clause)中增加并初始化新的變量,該變量不需要在lambda表達(dá)式所處的閉包域(enclosing scope)中存在;即使在閉包域中存在也會(huì)被新變量覆蓋(override)。新變量類型由它的初始化表達(dá)式推導(dǎo)。用途是可以從外層作用域中捕獲只供移動(dòng)的變量并使用它。
這是通過使用一個(gè)初始化表達(dá)式完成的:
auto lambda = [value = 1] {return value;}lambda函數(shù)lambda的返回值是1,說明value被初始化為1。被聲明的捕獲變量的類型會(huì)根據(jù)初始化表達(dá)式推斷,推斷方式與用auto聲明變量相同。
使用標(biāo)準(zhǔn)函數(shù)std::move可以使之被用以通過move捕獲:
auto ptr = std::make_unique<int>(10); //See below for std::make_uniqueauto lambda = [value = std::move(ptr)] {return *value;}函數(shù)返回類型推導(dǎo)[編輯]
C++11允許lambda函數(shù)根據(jù)return語句的表達(dá)式類型推斷返回類型。C++14為一般的函數(shù)也提供了這個(gè)能力。C++14還拓展了原有的規(guī)則,使得函數(shù)體并不是{return expression;}形式的函數(shù)也可以使用返回類型推導(dǎo)。[8]
為了啟用返回類型推導(dǎo),函數(shù)聲明必須將auto作為返回類型,但沒有C++11的后置返回類型說明符:
auto DeduceReturnType(); //返回類型由編譯器推斷如果函數(shù)實(shí)現(xiàn)中含有多個(gè)return語句,這些表達(dá)式必須可以推斷為相同的類型。[9]
使用返回類型推導(dǎo)的函數(shù)可以前向聲明,但在定義之前不可以使用。它們的定義在使用它們的翻譯單元(translation unit)之中必須是可用的。
這樣的函數(shù)中可以存在遞歸,但遞歸調(diào)用必須在函數(shù)定義中的至少一個(gè)return語句之后:[9]
auto Correct(int i) { if (i == 1) return i; // 返回類型被推斷為int else return Correct(i-1)+i; // 正確,可以調(diào)用}auto Wrong(int i){ if(i != 1) return Wrong(i-1)+i; // 不能調(diào)用,之前沒有return語句 else return i; // 返回類型被推斷為int}另一種類型推斷[編輯]
C++11中有兩種推斷類型的方式。auto根據(jù)給出的表達(dá)式產(chǎn)生具有合適類型的變量。decltype可以計(jì)算給出的表達(dá)式的類型。但是,decltype和auto推斷類型的方式是不同的。特別地,auto總是推斷出非引用類型,就好像使用了std::remove_reference一樣,而auto&&總是推斷出引用類型。然而decltype可以根據(jù)表達(dá)式的值類別(value category)和表達(dá)式的性質(zhì)推斷出引用或非引用類型:[8]
int i;int&& f();auto x3a = i; // x3a的類型是intdecltype(i) x3d = i; // x3d的類型是intauto x4a = (i); // x4a的類型是intdecltype((i)) x4d = (i); // x4d的類型是int&auto x5a = f(); // x5a的類型是intdecltype(f()) x5d = f(); // x5d的類型是int&&C++14增加了decltype(auto)的語法。允許auto的類型聲明使用decltype的規(guī)則。也即,允許不必顯式指定作為decltype參數(shù)的表達(dá)式,而使用decltype對于給定表達(dá)式的推斷規(guī)則。
decltype(auto)的語法也可以用于返回類型推導(dǎo),只需用decltype(auto)代替auto。[9]
放松的constexpr函數(shù)限制[編輯]
C++11引入了聲明為constexpr的函數(shù)的概念。聲明為constexpr函數(shù)的意義是:如果其參數(shù)均為合適的編譯期常量,則對這個(gè)constexpr函數(shù)的調(diào)用就可用于期望常量表達(dá)式的場合(如模板的非類型參數(shù),或枚舉常量的值)。如果參數(shù)的值在運(yùn)行期才能確定,或者雖然參數(shù)的值是編譯期常量,但不匹配這個(gè)函數(shù)的要求,則對這個(gè)函數(shù)調(diào)用的求值只能在運(yùn)行期進(jìn)行。 然而C++11要求constexpr函數(shù)只含有一個(gè)將被返回的表達(dá)式(也可以還含有static_assert聲明等其它語句,但允許的語句類型很少)。
C++14放松了這些限制。聲明為constexpr的函數(shù)可以含有以下內(nèi)容:[8]
任何聲明,除了:static或thread_local變量。沒有初始化的變量聲明。條件分支語句if和switch。所有的循環(huán)語句,包括基于范圍的for循環(huán)。表達(dá)式可以改變一個(gè)對象的值,只需該對象的生命期在聲明為constexpr的函數(shù)內(nèi)部開始。包括對有constexpr聲明的任何非const非靜態(tài)成員函數(shù)的調(diào)用。goto仍然不允許在constexpr函數(shù)中出現(xiàn)。
此外,C++11指出,所有被聲明為constexpr的非靜態(tài)成員函數(shù)也隱含聲明為const(即函數(shù)不能修改*this的值)。這點(diǎn)已經(jīng)被刪除,非靜態(tài)成員函數(shù)可以為非const。[10]
變量模板[編輯]
在C++之前的版本中,模板可以是函數(shù)模板或類模板(C++11引入了類型別名模板)。C++14現(xiàn)在也可以創(chuàng)建變量模板。在提案中給出的示例是變量pi,其可以被讀取以獲得各種類型的pi的值(例如,當(dāng)被讀取為整數(shù)類型時(shí)為3;當(dāng)被讀取為float,double,long double時(shí),可以是近似float,double或long double精度的值)包括特化在內(nèi),通常的模板的規(guī)則都適用于變量模板的聲明和定義。[6][11]
template<typename T>constexpr T pi = T(3.141592653589793238462643383);// 適用于特化規(guī)則 :template<>constexpr const char* pi<const char*> = "pi";聚合類成員初始化[編輯]
C++11增加了default member initializer,如果構(gòu)造函數(shù)沒有初始化某個(gè)成員,并且這個(gè)成員擁有default member initializer,就會(huì)用default member initializer來初始化成員。聚合類(aggregate type)的定義被改為明確排除任何含有default member initializer的類類型,因此,如果一個(gè)類含有default member initializer,就不允許使用聚合初始化。
C++14放松了這一限制,[8]含有default member initializer的類型也允許聚合初始化。如果在定義聚合體類型的對象時(shí),使用的花括號(hào)初始化列表沒有指定該成員的值,將會(huì)用default member initializer初始化它。[12]
struct CXX14_aggregate { int x; int y = 42;};CXX14_aggregate a = {1}; // C++14允許。a.y被初始化為42二進(jìn)制字面量[編輯]
C++14的數(shù)字可以用二進(jìn)制形式指定。[8]其格式使用前綴0b或0B。這樣的語法也被java、Python、Perl和D語言使用。
數(shù)字分位符[編輯]
C++14引入單引號(hào)(')作為數(shù)字分位符號(hào),使得數(shù)值型的字面量可以具有更好的可讀性。[13]
Ada、D語言、Java、Perl、Ruby等程序設(shè)計(jì)語言使用下劃線(_)作為數(shù)字分位符號(hào),C++之所以不和它們保持一致,是因?yàn)橄聞澗€已被用在用戶自定義的字面量的語法中。
auto integer_literal = 100'0000;auto floating_point_literal = 1.797'693'134'862'315'7E+308;auto binary_literal = 0b0100'1100'0110;auto silly_example = 1'0'0'000'00;deprecated 屬性[編輯]
deprecated屬性允許標(biāo)記不推薦使用的實(shí)體,該實(shí)體仍然能合法使用,但會(huì)讓用戶注意到使用它是不受歡迎的,并且可能會(huì)導(dǎo)致在編譯期間輸出警告消息。 deprecated可以有一個(gè)可選的字符串文字作為參數(shù),以解釋棄用的原因和/或建議替代者。
[[deprecated]] int f();[[deprecated("g() is thread-unsafe. Use h() instead")]]void g( int& x );void h( int& x );void test() { int a = f(); // 警告:'f'已棄用 g(a); // 警告:'g'已棄用:g() is thread-unsafe. Use h() instead}新的標(biāo)準(zhǔn)庫特性[編輯]
共享的互斥體和鎖[編輯]
C++14增加了一類共享的互斥體和相應(yīng)的共享鎖[14][15]。起初選擇的名字是std::shared_mutex,但由于后來增加了與std::timed_mutex相似的特性,std::shared_timed_mutex成為了更適合的名字。[16]
元函數(shù)的別名[編輯]
C++11定義了一組元函數(shù),用于查詢一個(gè)給定類型是否具有某種特征,或者轉(zhuǎn)換給定類型的某種特征,從而得到另一個(gè)類型。后一種元函數(shù)通過成員類型type來返回轉(zhuǎn)換后的類型,當(dāng)它們用在模板中時(shí),必須使用typename關(guān)鍵字,這會(huì)增加代碼的長度。
template <class T>type_object< typename std::remove_cv< typename std::remove_reference<T>::type >::type>get_type_object(T&);利用類型別名模板,C++14提供了更便捷的寫法。其命名規(guī)則是:如果標(biāo)準(zhǔn)庫的某個(gè)類模板(假設(shè)為std::some_class)只含有唯一的成員,即成員類型type,那么標(biāo)準(zhǔn)庫提供std::some_class_t<T>作為typename std::some_class::type的別名。
在C++14,擁有類型別名的元函數(shù)包括:remove_const、remove_volatile、remove_cv、add_const、add_volatile、add_cv、remove_reference、add_lvalue_reference、add_rvalue_reference、make_signed、make_unsigned、remove_extent、remove_all_extents、remove_pointer、add_pointer、aligned_storage、aligned_union、decay、enable_if、conditional、common_type、underlying_type、result_of、tuple_element。
template <class T>type_object<std::remove_cv_t<std::remove_reference_t<T>>>get_type_object(T&);關(guān)聯(lián)容器中的異構(gòu)查找[編輯]
C++標(biāo)準(zhǔn)庫定義了四個(gè)關(guān)聯(lián)容器類。set和multiset允許用戶根據(jù)一個(gè)值在容器中查找對應(yīng)的的同類型的值。map和multimap容器允許用戶指定鍵(key)和值(value)的類型,根據(jù)鍵進(jìn)行查找并返回對應(yīng)的值。然而,查找只能接受指定類型的參數(shù),在map和multimap中是鍵的類型,而在set和multiset容器中就是值本身的類型。
C++14允許通過其他類型進(jìn)行查找,只需要這個(gè)類型和實(shí)際的鍵類型之間可以進(jìn)行比較操作。[17]這允許std::set<std::string>使用const char*,或任何可以通過operator< 與std::string比較的類型作為查找的參數(shù)。
為保證向后兼容性,這種異構(gòu)查找只在提供給關(guān)聯(lián)容器的比較器允許的情況下有效。標(biāo)準(zhǔn)庫的泛型比較器,如std::less<>與std::greater<>允許異構(gòu)查找。[18]
標(biāo)準(zhǔn)自定義字面量[編輯]
C++11增加了自定義字面量(user-defined literals)的特性,使用戶能夠定義新的字面量后綴,但標(biāo)準(zhǔn)庫并沒有對這一特性加以利用。C++14標(biāo)準(zhǔn)庫定義了以下字面量后綴:[17]
"s",用于創(chuàng)建各種std::basic_string類型。"h"、"min"、"s"、"ms"、"us"、"ns",用于創(chuàng)建相應(yīng)的std::chrono::duration時(shí)間間隔。"if"、"i"、"il"用于創(chuàng)建相應(yīng)的 std::complex<float>、 std::complex<double> 和 std::complex<long double> 復(fù)數(shù)類型。auto str = "hello world"s; // 自動(dòng)推導(dǎo)為 std::stringauto dur = 60s; // 自動(dòng)推導(dǎo)為 chrono::secondsauto z = 1i; // 自動(dòng)推導(dǎo)為 complex<double>兩個(gè)"s"互不干擾,因?yàn)楸硎咀址闹荒軐ψ址置媪坎僮?,而表示秒的只針對?shù)字。[19]
通過類型尋址多元組[編輯]
C++11引入的std::tuple類型允許不同類型的值的聚合體用編譯期整型常數(shù)索引。C++14還允許使用類型代替常數(shù)索引,從多元組中獲取對象。[17]若多元組含有多于一個(gè)這個(gè)類型的對象,將會(huì)產(chǎn)生一個(gè)編譯錯(cuò)誤:[20]
tuple<string, string, int> t("foo", "bar", 7);int i = get<int>(t); // i == 7int j = get<2>(t); // Same as before: j == 7string s = get<string>(t); //Compiler error due to ambiguity較小的標(biāo)準(zhǔn)庫特性[編輯]
std::make_unique可以像std::make_shared一樣使用,用于產(chǎn)生std::unique_ptr對象。[6]
std::is_final,用于識(shí)別一個(gè)class類型是否禁止被繼承。
std::integral_constant增加了一個(gè)返回常量值的operator()。[17]
全局std::begin/std::end函數(shù)之外,增加了std::cbegin/std::cend函數(shù),它們總是返回常量迭代器(constant iterators)。
已被移除或是不包含在C++14標(biāo)準(zhǔn)的特性[編輯]
因?yàn)镃++14的主要目的是漏洞修復(fù)和小的改進(jìn),一些重量級(jí)的特性被從C++14中移除,其中有部分將加入C++17標(biāo)準(zhǔn)。
關(guān)于數(shù)組的擴(kuò)展[編輯]
在C++11和之前的標(biāo)準(zhǔn)中,在堆棧上分配的數(shù)組被限制為擁有一個(gè)固定的、編譯期確定的長度。這一擴(kuò)展允許在堆棧上分配的一個(gè)數(shù)組的最后一維具有運(yùn)行期確定的長度。[6]
運(yùn)行期確定長度的數(shù)組不可以作為對象的一部分,也不可以具有全局存儲(chǔ)期,他們只能被聲明為局部變量。運(yùn)行期確定長度的數(shù)組也可以使用C++11的基于范圍的for循環(huán)。[21]
同時(shí)還將添加std::dynarray類型,它擁有與std::vector和std::array相似的接口。代表一個(gè)固定長度的數(shù)組,其大小在運(yùn)行期構(gòu)造對象時(shí)確定。std::dynarray類被明顯地設(shè)計(jì)為當(dāng)它被放置在棧上時(shí)(直接放置在棧上,或作為另一個(gè)棧對象的成員),可以使用棧內(nèi)存而不是堆內(nèi)存。
由于一些設(shè)計(jì)無法達(dá)成一致,這一擴(kuò)展已被放棄。
Optional值[編輯]
類似于C#中的可空類型,optional類型可能含有或不含有一個(gè)值。這一類型基于Boost的boost::optional類,而添加了C++11和C++14中的新特性,諸如移動(dòng)和in-place構(gòu)造。它不允許用在引用類型上。這個(gè)類被專門的設(shè)計(jì)為一個(gè)literal type(如果模板參數(shù)本身是一個(gè)literal type),因此,它在必要的情況下含有constexpr構(gòu)造函數(shù)。[22]
Concepts Lite[編輯]
參見:概念 (C++)被C++11拒絕后,Concepts受到徹底的修改。Concepts Lite是Concepts的一個(gè)部分,僅包含類型約束,而不含concept_map和axiom[23]。 ISO/IEC TS 19217:2015 Information technology -- Programming languages -- C++ Extensions for concepts已出版。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注