支援 C++11/14/17 功能(現代 C++
支援 C++11/14/17 功能(現代 C++)
若要了解有關 Visual Studio 2017 RC 的最新文件,請參閱 Visual Studio 2017 RC 文件。
本文描述了 Visual C++ 中的 C++11/14/17 功能。
本文內容
C++11 功能列表
Visual C++ 實現了 C++11 核心語言規範 中的絕大多數功能、許多 C++14 庫功能和某些為 C++17 建議的功能。 下表列出了 C++11/14/17 核心語言功能及其在 Visual Studio 2010、Visual Studio 2012 中的 Visual C++、Visual Studio 2013 中的 Visual C++ 和 Visual Studio 2015 中 Visual C++ 中的實現狀態。
C++11 核心語言功能表
C++11 核心語言功能 | Visual Studio 2010 | Visual Studio 2012 | Visual Studio 2013 | Visual Studio 2015 |
---|---|---|---|---|
右值引用 v0.1、v1.0、v2.0、v2.1、v3.0 | 2.0 版 | 2.1* 版 | 2.1* 版 | v3.0 |
引用限定符 | 否 | 否 | 否 | 是 |
非靜態資料成員初始值設定項 | 否 | 否 | 是 | |
可變引數模板 v0.9、v1.0 | 否 | 否 | 是 | 是 |
初始值設定項列表 | 否 | 否 | 是 | 是 |
static_assert | 是 | 是 | 是 | 是 |
auto v0.9、v1.0 | v1.0 | v1.0 | v1.0 | 是 |
結尾返回型別 | 是 | 是 | 是 | 是 |
Lambdas v0.9、v1.0、v1.1 | v1.0 | v1.1 | v1.1 | 是 |
decltype v1.0、v1.1 | v1.0 | v1.1** | v1.1 | 是 |
右尖括號 | 是 | 是 | 是 | 是 |
函式模板的預設模板引數 | 否 | 否 | 是 | 是 |
表示式 SFINAE | 否 | 否 | 否 | 否 |
別名模板 | 否 | 否 | 是 | 是 |
Extern 模板 | 是 | 是 | 是 | 是 |
nullptr | 是 | 是 | 是 | 是 |
強型別的列舉 | 部分 | 是 | 是 | 是 |
前向宣告列舉 | 否 | 是 | 是 | 是 |
特性 | 否 | 否 | 否 | 是 |
constexpr | 否 | 否 | 否 | 是 |
對齊方式 | TR1 | 部分 | 部分 | 是 |
委託建構函式 | 否 | 否 | 是 | 是 |
繼承建構函式 | 否 | 否 | 否 | 是 |
顯式轉換運算子 | 否 | 否 | 是 | 是 |
char16_t/char32_t | 否 | 否 | 否 | 是 |
Unicode 字串文字 | 否 | 否 | 否 | 是 |
原始字串文字 | 否 | 否 | 是 | 是 |
文字中的通用字元名 | 否 | 否 | 否 | 是 |
使用者定義的文字 | 否 | 否 | 否 | 是 |
標準佈局和普通型別 | 否 | 是 | 是 | 是 |
預設函式和已刪除的函式 | 否 | 否 | 是* | 是 |
擴充套件的友元宣告 | 是 | 是 | 是 | 是 |
擴充套件的 sizeof | 否 | 否 | 否 | 是 |
內聯名稱空間 | 否 | 否 | 否 | 是 |
無限制的聯合 | 否 | 否 | 否 | 是 |
作為模板引數的本地和未命名型別 | 是 | 是 | 是 | 是 |
基於範圍的 for 迴圈 | 否 | 是 | 是 | 是 |
override 和 final v0.8、v0.9、v1.0 | 部分 | 是 | 是 | 是 |
最低 GC 支援 | 是 | 是 | 是 | 是 |
noexcept | 否 | 否 | 否 | 是 |
[本文內容]
C++11 核心語言功能表:併發
C++11 核心語言功能:併發 | Visual Studio 2010 | Visual Studio 2012 | Visual Studio 2013 | Visual Studio 2015 |
---|---|---|---|---|
改寫的序列點 | 不可用 | 不可用 | 不可用 | 是 |
原子 | 否 | 是 | 是 | 是 |
強比較和交換 | 否 | 是 | 是 | 是 |
雙向界定 | 否 | 是 | 是 | 是 |
記憶體模型 | 不可用 | 不可用 | 不可用 | 是 |
資料依賴項排序 | 否 | 是 | 是 | 是 |
資料依賴項排序:函式批註 | 否 | 否 | 否 | 是 |
exception_ptr | 是 | 是 | 是 | 是 |
quick_exit | 否 | 否 | 否 | 是 |
訊號處理程式中的原子化 | 否 | 否 | 否 | 否 |
執行緒本地儲存區 | 部分 | 部分 | 部分 | 是 |
神奇的靜態物件 | 否 | 否 | 否 | 是 |
[本文內容]
C++11 核心語言功能:C99
C++11 核心語言功能:C99 | Visual Studio 2010 | Visual Studio 2012 | Visual Studio 2013 | Visual Studio 2015 |
---|---|---|---|---|
__func__ | 部分 | 部分 | 部分 | 是 |
C99 前處理器 | 部分 | 部分 | 部分 | 部分 |
long long | 是 | 是 | 是 | 是 |
擴充套件的整型 | 不可用 | 不可用 | 不可用 | 不可用 |
[本文內容]
C++ 14 核心語言功能
功能 | Visual Studio 2013 | Visual Studio 2015 |
上下文轉換的已調整 workding | 是 | 是 |
二進位制文字 | 否 | 是 |
auto 和 decltype(auto) 返回型別 | 否 | 是 |
init-capture | 否 | 是 |
泛型 lambda | 否 | 是 |
變數模板 | 否 | 否 |
擴充套件的 constexpr | 否 | 否 |
聚合的 NSDMI | 否 | 否 |
避免/合成分配 | 否 | 否 |
[已棄用] 特性 | 否 | 否 |
大小經過調整的分配 | 否 | 是 |
數字分隔符 | 否 | 是 |
C++17 建議的核心語言功能
功能 | Visual Studio 2013 | Visual Studio 2015 |
針對自動使用大括號內的初始值設定項列表的新建規則 | 否 | 否 |
簡要靜態斷言 | 否 | 否 |
模板-引數模板的型別名稱 | 否 | 否 |
刪除三字元組 | 是 | 是 |
巢狀的名稱空間定義 | 否 | 否 |
N4259 std::uncaught_exceptions() | 否 | 否 |
N4261 修復限定轉換 | 否 | 否 |
N4266 名稱空間和列舉器的特性 | 否 | 否 |
N4267 u8 字元文字 | 否 | 否 |
N4268 允許更多非型別模板引數 | 否 | 否 |
N4295 Fold 摺疊表示式 | 否 | 否 |
等待/繼續 | 否 | 是 |
功能表指南
右值引用
說明 |
---|
以下描述中的版本識別符號(v0.1、v1.0、v2.0、v2.1、v3.0)僅用來演示 C++11 的發展。 標準本身不會使用它們。 |
N1610“通過右值澄清類物件的初始化”是早期在不引用右值的情況下支援移動語義的一種嘗試。 為方便討論,我們稱之為“右值引用 0.1 版”。 它由“右值引用 v1.0”取代。 “右值引用 v2.0”是 Visual Studio 2010 中的 Visual C++ 功能的基礎,它禁止將右值引用繫結到左值,因此可以解決主要的安全性問題。 “右值引用 v2.1”重新定義了此規則。 讓我們看一下 vector<string>::push_back()
,它具有過載 push_back(const string&)
和 push_back(string&&)
以及呼叫 v.push_back("strval")
。 表示式 "strval"
是字串,並且是左值。 (其他文字為右值,如整數 1729,但字串有些特殊,因為它們是陣列。) “右值引用 2.0 版”規則顯示,string&&
無法繫結到 "strval"
,因為 "strval"
是左值,因此 push_back(const string&)
是唯一可行的過載。 這將建立一個臨時 std::string
,並將它複製到向量中,然後銷燬效率不太高的臨時 std::string
。 “右值引用 2.1 版”規則確認,將 string&&
繫結到 "strval"
將建立臨時 std::string
,並且該臨時字串為右值。 因此,push_back(const string&)
和 push_back(string&&)
都是可行的,但首選 push_back(string&&)
。 將構造一個臨時 std::string
,然後將它移至向量中。 這樣效率更高。
“右值引用 v3.0”將新增新規則,以在特定條件下自動生成移動建構函式和移動賦值運算子。 這是在 Visual Studio 2015 中實現的。
[本文內容]
Lambdas
在 lambda 函式選入到工作檔案(“0.9”版)並且已新增可變的 lambda(“1.0”版)之後,標準化委員會全面修訂了措詞。 這產生了 lambda“1.1”版,這個版本現在已完全受支援。 lambda 1.1 版的措詞闡明瞭在特殊案例(例如引用靜態成員或巢狀 lambda)中會發生的情況。 這將修復由複雜 lambda 觸發的問題。 此外,無狀態的 lambda 現在可轉換為函式指標。 這沒有包含在 N2927 措詞中,但是無論如何都會將它計作 lambda 1.1 版的一部分。C++11 5.1.2 [expr.prim.lambda]/6 具有以下說明:“無 lambda-capture
的 lambda-expression
的閉包型別使用一個公共的非虛擬、非顯式常量轉換函式指向一個具有與閉包型別的函式呼叫運算子相同的引數和返回型別的函式。 此轉換函式返回的值應為一個函式的地址,呼叫該函式時,其效果和呼叫閉包型別的函式呼叫運算子相同。” (Visual Studio 2012 中的 Visual C++ 實現的效果甚至更好,因為它使無狀態的 lambda 可轉換為具有任意呼叫約定的函式指標。 當你在使用期待像 __stdcall
函式指標這類物件的 API 時,這點很重要。)
[本文內容]
decltype
在 decltype 選入到工作檔案(1.0 版)後,在最後時刻收到了一個小的但很重要的修復(1.1 版)。 這對從事 STL 和 Boost 工作的程式設計師很有好處。
[本文內容]
強型別/前向宣告列舉
Visual Studio 2010 中的 Visual C++ 部分支援 強型別的列舉(具體而言,支援有關顯式指定的基礎型別部分)。 現在這些在 Visual Studio 中已完全實現,前向宣告列舉的 C++11 語義也已完全實現。
[本文內容]
對齊方式
選入工作檔案的對齊方式提案中的核心語言關鍵字 alignas
/alignof
在 Visual Studio 2015 中已實現。 Visual Studio 2010 中的 Visual C++ 具有來自 TR1 的 aligned_storage
。Visual Studio 2012 中的 Visual C++ 已將 aligned_union
和 std::align()
新增到標準庫,而且重大的問題已在 Visual Studio 2013 中的 Visual C++ 中修復。
[本文內容]
標準佈局和普通型別
來自 N2342“POD 重新訪問;解決核心問題 568(修訂 5)”的公開更改是將 is_trivial
和 is_standard_layout
新增到標準模板庫的 <type_traits>
。 (N2342 修改了大量核心語言措詞,但無需進行編譯器更改。) 這些型別特徵在 Visual Studio 2010 的 Visual C++ 中已提供,但它們只是複製了 is_pod
。 因此,本文件中之前的表顯示“不支援”。 它們現在由設計用於給出精確答案的編譯器掛鉤驅動。
STL 的 common_type 在 Visual Studio 2013 中的 Visual C++ 中得到了迫切需要的修復。common_type<>
的 C++11 規範導致意外後果;具體而言,它使 common_type<int, int>::type
返回 int&&
。 因此,Visual Studio 2013 中的 Visual C++ 可實現建議用於庫工作組問題 2141 的解決方法,使 common_type<int, int>::type
返回 int
。
作為此更改的副作用,標識用例不再起作用(common_type<T>
並不總是產生 T
型別)。 這將遵循建議的解決方法,但其將中斷依賴於先前行為的所有程式碼。
如果需要標識型別特徵,請不要使用 std::identity
中定義的非標準 <type_traits>
,因為它對 <void>
無效。 相反,實現你自己的標識型別特徵以滿足你的需求。 以下是一個示例:
C++
template <typename T> struct Identity { typedef T type; };
說明 |
---|
有關其他重大更改,請參閱Visual C++ 2015 中的重大更改。 |
[本文內容]
預設函式和已刪除的函式
這些函式現在均受支援,但此種情況例外:對於預設函式,不支援使用 =default
請求識別成員的移動建構函式和移動賦值運算子。 複製和移動操作並不按照標準規定的方式進行精確互動 - 例如,指定刪除移動會同時禁止顯示覆制操作,但 Visual Studio 2013 中的 Visual C++ 不會。
有關如何使用預設函式和已刪除的函式的資訊,請參閱函式。
[本文內容]
override 和 final
這經歷了短暫而複雜的發展。 最初,在 0.8 版中,具有 [[override
]]、[[hiding
]] 和 [[base_check
]] 特性。 然後在 0.9 版中,消除了這些特性並將其替換為上下文關鍵字。 最後,在 1.0 版中,將它們精簡為類的“final
”以及函式的“override
”和“final
”。 這使它成為一個獲得提升的擴充套件,因為 Visual Studio 2010 中的 Visual C++ 已支援對函式使用此“override
”語法,並且語義相當接近於 C++11 中的語義。 “final
”也受支援,但拼寫不同(“sealed”)。 現在完全支援“override
”和“final
”的標準拼寫和語義。 有關詳細資訊,請參閱 override 說明符 和 final 說明符。
[本文內容]
原子化及更多資訊
原子化、強比較和交換、雙向界定和資料依賴項排序指定現在已實現的標準庫機制。
相關 STL 標頭: <atomic>、<chrono>、<condition_variable>、<future>、<mutex>、<ratio>、<scoped_allocator> 和 <thread>。
[本文內容]
C99 __func__ 和前處理器規則
C++11 核心語言功能:C99 表列出了兩個項的“部分”實現。 對於預定義識別符號 __func__
,列出“分部”,因為對非標準擴充套件 __FUNCDNAME__
、__FUNCSIG__
和 __FUNCTION__
提供了支援。 有關詳細資訊,請參閱 預定義的巨集。 對於 C99 前處理器規則,列出“分部”,因為支援可變引數巨集。 有關詳細資訊,請參閱 Variadic 巨集。
[本文內容]
標準庫功能
這涵蓋核心語言。 至於 C++11 標準庫,我們雖沒有漂亮的功能比較表,但 Visual Studio 2012 中的 Visual C++ 已實現此功能,但具有兩個例外。 首先,當某個庫功能依賴於編譯器中缺少的功能時,該功能要麼是模擬的(例如,make_shared<T>()
的模擬可變引數模板),要麼沒有實現。 (僅有少數情況現在已經在 Visual Studio 2013 中的 Visual C++ 中完全實現,其中最值得注意的是 <initializer_list>
。) C99 已在 Visual Studio 2013 中的 Visual C++ 和提供的 C++ 包裝器標頭中實現,並且例外情況非常少。 有關更多資訊,請參閱 Visual Studio 2013 中的 C99 庫支援。
下面列出了 Visual Studio 2012 中的 Visual C++ 和 Visual Studio 2013 中的 Visual C++ 中的部分更改:
定位:根據 C++11 的要求,emplace()
/emplace_front()
/emplace_back()
/emplace_hint()
/emplace_after()
已在所有包含“任意”數量引數的容器中實現(請參見“模擬的可變引數”部分)。 例如,vector<T>
具有“template <typename... Args> void emplace_back(Args&&... args)
”(它在向量的後面從任意數量的任意引數時直接構造元素型別 T,這稱為“完全轉發”)。 這相對於 push_back(T&&)
(將涉及額外的移動構造和析構)效率更高。
可變引數: Visual Studio 2012 中的 Visual C++ 具有用於模擬可變引數模板的方案。 在 Visual Studio 2013 中的 Visual C++ 中,取消了模擬,並完全實現了可變引數。 如果你的程式碼依賴舊的模擬可變引數行為,則必須修復它。 但是,切換到實際可變引數模板增加了編譯次數,並降低了編譯器的記憶體消耗。
顯式轉換運算子:在核心語言中,顯式轉換運算子是一項常規功能 — 例如,你可以具有 explicit operator MyClass()
。 但是,標準庫當前僅使用一種形式:explicit operator bool()
,這使類成為安全的布林值可測試的類。 (無格式“operator bool()
”是非常危險的。) 過去,Visual C++ 模擬了帶有 explicit operator bool()
的 operator pointer-to-member()
,這導致各種問題,並且效率有些低下。 現在,完全移除了此“虛擬 bool”工作區。
隨機性: uniform_int_distribution
現在是完全公平的,並且在 <algorithm>
中實現了 shuffle()
,這樣便可以直接接受統一隨機數生成器,如 mersenne_twister
。
防止過載 address-of 運算子:C++98/03 禁止 STL 容器的元素過載其 address-of 運算子。 這是類似 CComPtr
的類完成的操作,因此使 STL 避免此類過載需要類似 CAdapt
的幫助程式類。 開發 Visual Studio 2010 中的 Visual C++ 時,STL 更改使其在更多情況下拒絕過載 address-of 運算子。 C++11 更改了相關要求,使得過載 address-of 運算子可接受。 Visual Studio 2010 中的 C++11 和 Visual C++ 提供幫助程式函式 std::addressof()
,此函式可獲取物件的真實地址(無論運算子是否過載)。 在釋出 Visual Studio 2010 中的 Visual C++ 之前,我們已嘗試將“&elem
”的匹配項替換為具有一定抵抗性的“std::addressof(elem)
”。Visual Studio 2012 中的 Visual C++ 更進一步,這樣過載 address-of 運算子的類就能在整個 STL 中使用了。
Visual Studio 2012 中的 Visual C++ 在下列方面超出了 C++11 的範圍:
SCARY 迭代器:實現了 SCARY 迭代器,如 N2911“在泛型類中最小化依賴項以獲得更快且更小的程式”和 N2980“SCARY 迭代器分配和安裝,第一版”中所述,這在 C++11 標準是允許的,但不是必需的。
檔案系統:已新增 TR2 建議中的 <filesystem>
標頭。 它提供 recursive_directory_iterator
和其他有趣功能。 在 TR2 的工作凍結之前,由於 C++0x 很晚才投入執行且將更改為 C++11,因此從 Boost.Filesystem V2 派生出了 2006 協議。 它稍後改進為 Boost.Filesystem V3,這在 Visual Studio 2015 中實現。
一個主要優化! 現在,我們的所有容器相對於當前的表示形式都具有最小的合適大小。 這指的是容器物件本身,而不是它們指向的內容。 例如,std::vector
包含三個原始指標。 在 Visual Studio 2010 中的 Visual C++ 中,x86 釋出模式 std::vector
為 16 位元組。 在 Visual Studio 2012 中的 Visual C++ 中,它為 12 位元組,這是最小的合適大小。 如果你的程式有 100,000 個向量,則 Visual Studio 2012 中的 Visual C++ 將為你節省 400,000 位元組,這很了不起。 減少記憶體使用率可節省空間和時間。
這是通過避免儲存空的分配器和比較運算子來實現的,因為 std::allocator
和 std::less
是無狀態的。 (只要自定義分配器/比較運算子是無狀態的,也會為它們啟用這些優化。 顯然,無法避免有狀態的分配器/比較運算子的儲存,但這種情況極為少見。)
Visual Studio 2013 中的 Visual C++ 實現一些關鍵的 C++ 14 庫功能:
-
“透明運算子函子”
less<>
、greater<>
、plus<>
、multiplies<>
等。 -
make_unique<T>(args...)
和make_unique<T[]>(n)
-
cbegin()
/cend()
、rbegin()
/rend()
和crbegin()
/crend()
非成員