C++ 14新特性個人總結

在這里插入圖片描述

variable templates

變量模板。這個特性允許模板被用于定義變量,就像之前模板可以用于定義函數或類型一樣。變量模板為模板編程帶來了新的靈活性,特別是在定義泛化的常量和元編程時非常有用。
在這里插入圖片描述

變量模板的基本語法

變量模板的聲明遵循以下基本語法:

template<typename T>
constexpr T someValue = /* some value depending on T */;

這里,T是一個類型參數,someValue是根據T變化的一個變量。

示例:定義一個泛化的π值

考慮一個簡單的例子,我們想要定義一個依據類型變化的π值,以便能夠獲取不同精度的π值(例如,floatdoublelong double等)。

#include <iostream>template<typename T>
constexpr T pi = T(3.1415926535897932385);int main() {std::cout << "pi<float> = " << pi<float> << std::endl;std::cout << "pi<double> = " << pi<double> << std::endl;std::cout << "pi<long double> = " << pi<long double> << std::endl;return 0;
}

這個例子中,我們定義了一個變量模板pi,其類型是模板參數T。因此,我們可以請求pi的不同類型版本,獲取相應精度的π值。

注意事項

  • 類型完整性:變量模板在實例化時要求其類型參數必須是完整類型。
  • 模板參數限制:和函數或類模板一樣,變量模板不能推導其模板參數。

generic lambdas

泛型Lambda表達式,這大大增強了Lambda的靈活性和通用性。泛型Lambda允許Lambda的參數類型自動推導,更重要的是,它允許Lambda使用模板參數。這意味著,你可以寫出更為通用的Lambda表達式,它們能夠處理多種不同類型的數據,而不需要為每種類型編寫特定的代碼。

泛型Lambda的基本用法

在C++11中,Lambda參數的類型必須是顯式聲明的。而在C++14中,你可以使用auto關鍵字,讓編譯器自動推導參數的類型。這不僅僅是一個簡化的語法糖,它實際上隱式地將Lambda轉換成了一個模板。

例如,一個可以比較兩個值的Lambda在C++14中可以寫成:

auto compare = [](auto a, auto b) {return a < b;
};

這個Lambda可以用于比較任意兩個可以進行<操作的類型的值。

實現原理

當編譯器遇到泛型Lambda的時候,它實際上為Lambda自動生成了一個模板類。每次調用泛型Lambda時,編譯器根據傳遞給Lambda的參數類型,實例化出一個特定的模板實例。這就是C++14泛型Lambda如何提供類型通用性的基本原理。

使用場景

泛型Lambda可以在很多場合下簡化代碼,特別是與STL算法一起使用時。例如,使用泛型Lambda在一個容器中查找一個元素:

std::vector<int> v = {1, 2, 3, 4, 5};
int to_find = 3;
auto found = std::find_if(v.begin(), v.end(), [to_find](auto elem) { return elem == to_find; });

這段代碼使用了泛型Lambda來定義查找條件,這使得相同的Lambda可以應用于不同類型的容器和元素。

注意事項

  • 捕獲表達式的自動類型推導:泛型Lambda可以捕獲外部變量,但是這些捕獲的變量類型必須在Lambda表達式創建時就已經確定。這意味著不能捕獲泛型Lambda自身作為變量,因為在創建時Lambda的類型還未確定。

  • Lambda不能被重載或特化:與函數模板不同,Lambda表達式不能被重載或特化。這意味著同一個Lambda表達式必須能夠處理所有它可能被調用的的類型。

  • 遞歸調用:泛型Lambda表達式不能直接遞歸調用自己,因為auto類型參數不允許在Lambda內部推導其自身類型

lambda init-capture

C++14引入了一個新的Lambda表達式特性:初始化捕獲(init-capture),也被稱為廣義Lambda捕獲或Lambda初始化。這項特性讓我們能夠在Lambda表達式的捕獲列表中,直接定義并初始化新的變量。這提供了更加靈活的變量捕獲方式,允許在Lambda表達式創建時構造新的對象或執行復雜的初始化。

基本語法

初始化捕獲的基本語法是在Lambda捕獲列表中使用[name = expression]形式,其中name是在Lambda體中使用的新變量的名稱,而expression是用于初始化該變量的表達式。例如:

int x = 42;
auto lambda = [y = x + 1] { return y; };
std::cout << lambda(); // 輸出 43

在這個例子中,通過初始化捕獲創建了一個名為y的新變量,并將其初始化為x + 1的值。y在Lambda內部可用,就像任何其他捕獲的變量一樣。

特點與用途

初始化捕獲的引入解決了C++11中存在的一些局限性:

  • 移動語義支持:在C++11中,Lambda只能通過值或引用捕獲外部變量,不能方便地捕獲通過移動語義獲得的對象。C++14通過初始化捕獲支持移動語義,使得能夠移動而非復制對象到Lambda表達式內部。

    auto p = std::make_unique<int>(42);
    auto lambda = [ptr = std::move(p)] { return *ptr; };
    
  • 復雜的初始化:初始化捕獲允許在Lambda捕獲列表中執行復雜的表達式計算,無需在Lambda外部單獨聲明和初始化變量。

  • 避免不必要的捕獲:有時我們希望Lambda表達式依賴于從外部變量派生的值,而不直接依賴這些外部變量本身。通過初始化捕獲,可以避免不必要地捕獲外部變量,減少資源捕獲的開銷。

注意事項

  • 初始化捕獲只能創建拷貝或通過移動語義創建的變量。這意味著,你不能通過初始化捕獲來直接聲明一個引用類型的變量。例如,以下代碼是不合法的:
int x = 42;
auto lambda = [&y = x] { return y; }; // 錯誤:不能通過初始化捕獲來創建引用

relaxed restrictions on constexpr functions

在C++14中,對constexpr函數的限制相較于C++11有了顯著放寬。constexpr函數或變量表達的是它們可以在編譯時被求值,這對于提高程序的性能和安全性非常重要。在C++11中,標記為constexpr的函數受到了很多限制,使得它們的用途相對有限。然而,C++14放寬了這些限制,使得constexpr函數變得更加靈活和強大。

C++11中的constexpr函數限制包括:

  • 函數體內只能包含一個單一的返回語句。
  • 不能有任何變量聲明。
  • 不能有任何循環或分支語句。

C++14放寬的限制:

  1. 多條語句:C++14允許constexpr函數包含多條語句,使得你可以在constexpr函數中執行更復雜的計算。

  2. 局部變量:允許在constexpr函數內部聲明和使用局部變量,只要這些變量的類型也都是字面類型(Literal Type)。

  3. 循環和分支:在C++14中,constexpr函數現在可以使用循環和條件分支,這大大增加了它們的靈活性和能力。

  4. 遞歸:由于允許使用多條語句和條件分支,constexpr函數現在也支持遞歸調用。

示例對比:

C++11中的constexpr函數:

constexpr int factorial(int n) {return n <= 1 ? 1 : (n * factorial(n - 1));
}

C++14中的constexpr函數:

constexpr int factorial(int n) {int result = 1;for(int i = 1; i <= n; ++i) {result *= i;}return result;
}

在C++14的例子中,我們利用了局部變量、循環,以及允許在constexpr函數中包含多條語句的特性。

注意點:

  • 即使C++14放寬了對constexpr函數的限制,但是為了在編譯時求值,函數的所有輸入和邏輯仍然需要在編譯時是已知的。
  • constexpr函數也可以在運行時被調用,如果其參數在編譯時不是已知的。在這種情況下,它們就像普通函數那樣工作。

binary literals

二進制字面量,使得開發者可以直接在代碼中以二進制形式表示整數。這一特性對于底層編程、位操作或者對內存布局有特定要求的場景尤為有用。在C++14之前,表達二進制數據通常需要使用十六進制或八進制,盡管這些方法也相對直觀,但直接使用二進制字面量無疑能讓代碼的意圖更加明顯。
在這里插入圖片描述

使用方法

二進制字面量通過在數字前加0b0B前綴來表示。后續緊跟二進制數字(0或1)。

// C++14 二進制字面量示例
int a = 0b1010;  // 等于十進制的10
int b = 0B0011;  // 等于十進制的3

這種表示方法使得表達和理解涉及位操作的代碼變得更加直觀和簡潔。

注意事項

  • 前綴規定:二進制字面量必須以0b0B前綴開始。沒有此前綴,數字會被解釋為十進制數。

  • 類型默認為int:就像十進制和十六進制字面量一樣,未經明確指定的二進制字面量將被視為int類型。如果字面量超出了int類型的范圍,這可能導致未定義行為或編譯錯誤。

digit separators

數字分隔符,允許在數值字面量中使用單引號'作為分隔符,以提高數值的可讀性。這對于編寫涉及大數值的代碼特別有用,使得這些大數值更容易閱讀和理解。

使用方法

數字分隔符可以在整數、浮點數以及二進制、八進制、十六進制數字字面量中使用。分隔符可以放置在數字之間的任何位置,但不能放置在數字的開頭或結尾。此外,分隔符不能連續使用。

以下是一些使用數字分隔符的示例:

long long earth_population = 7'800'000'000; // 世界人口約78億
unsigned long distance_to_moon = 384'400; // 月球距離地球大約384,400千米
double avogadro_number = 6.022'140'76e23; // 阿伏伽德羅常數
int binary_data = 0b1010'0110'1101'0011; // 二進制字面量

注意事項

  • 位置限制:數字分隔符(單引號')不能放置在數值字面量的開頭或結尾。此外,分隔符之間至少要有一位數字,不允許連續使用分隔符。

  • 前綴后立即使用:對于二進制(0b0B)、八進制(0)、十六進制(0x0X)字面量,分隔符不能緊跟數值前綴后立即出現。比如,0x'FF是不合法的,正確的寫法應該是0xFF

  • 浮點數及科學記數法:在浮點數和使用科學記數法的字面量中,分隔符同樣不能用在小數點或指數標識符(eE)之前或之后立即出現。

return type deduction for functions

函數返回類型推導,允許編譯器從函數體中推導函數的返回類型,而不需要顯式地指定。這一特性大大提高了C++語言的靈活性和表達力,尤其是在編寫模板代碼和Lambda表達式時。
在這里插入圖片描述

使用方法

要使用函數返回類型推導,可以在函數聲明中使用auto作為返回類型。編譯器會根據函數體中return語句的類型來自動推導整個函數的返回類型。

auto Add(int x, int y) {return x + y;  // 返回類型根據返回值推導為int
}auto GetMessage() {return "Hello, World!";  // 返回類型根據返回值推導為const char*
}
  • 如果函數包含多個return語句,那么所有return語句的返回類型必須相同,或者必須有一個明確的、可以自動轉換的公共類型,否則會導致編譯錯誤。

  • 函數不能僅由一個不返回任何值的return語句構成,這樣編譯器無法推導出返回類型。

  • 在某些復雜的情況下,顯式指定返回類型可能更加清晰和直觀。

適用場景

函數返回類型推導特別適用于如下場景:

  • 模板編程:在模板編程中,函數的返回類型可能依賴于模板參數,使用auto可以避免復雜的類型聲明。

  • Lambda表達式:Lambda表達式在C++11中引入時就支持返回類型推導,C++14將這一特性擴展到了所有函數。

  • 減少冗余:在某些函數的返回類型非常明顯的情況下,使用返回類型推導可以減少代碼的冗余,并提高代碼的簡潔性和可讀性。

注意事項

  1. 一致的返回類型:如果函數包含多個return語句,所有return語句必須具有相同的類型,或者它們的類型能夠隱式轉換為一個共同的類型。否則,編譯器將無法推導出一個確定的返回類型,導致編譯錯誤。

  2. 無返回值的情況:使用auto作為返回類型時,函數體不能僅包含不返回值的return語句(例如,空的return;)。這是因為編譯器需要通過return語句的類型來推導函數的返回類型。

  3. 遞歸函數的限制:對于遞歸函數,編譯器可能無法在所有情況下準確推導出返回類型。

aggregate classes with default non-static member initializers

在C++14中,聚合類(Aggregate classes)的特性得到了增強,允許包含默認的非靜態成員初始化器(Default non-static member initializers)。這意味著聚合類除了原有的特點,比如沒有用戶定義的構造函數(User-defined constructors)、沒有私有或保護的非靜態數據成員、沒有基類和虛函數等,現在還可以為其非靜態成員指定默認初始值。
在這里插入圖片描述

聚合類定義

在C++14之前,聚合類主要用于簡單地將數據組合在一起,沒有復雜的類初始化語義。具體來說,一個聚合類滿足以下條件:

  • 沒有用戶定義的構造函數
  • 沒有私有或保護的非靜態數據成員
  • 沒有虛函數
  • 沒有基類

C++14中的變化

C++14允許聚合類的非靜態數據成員擁有默認的初始化器。這增加了聚合類的靈活性和易用性,允許它們在定義時指定成員的初始狀態,而不需要用戶定義的構造函數。

struct Point {int x{0};  // 默認初始化為0int y{0};
};Point p;  // p.x和p.y都默認初始化為0
Point q = {1, 2};  // 通過聚合初始化設置x為1,y為2

std::make_unique

內存管理工具——std::make_unique。這個函數模板用于創建并返回一個指向動態分配對象的std::unique_ptr,簡化了動態內存分配的過程并幫助避免內存泄漏。
在這里插入圖片描述

使用方法

std::make_unique函數模板的基本語法如下:

std::unique_ptr<T> make_unique<Args>(Args&&... args);

其中,T是動態分配對象的類型,Args是構造函數的參數列表。

示例:

auto ptr = std::make_unique<int>(42);  // 創建一個指向int的std::unique_ptr并初始化為42struct Point {int x;int y;
};auto point = std::make_unique<Point>(Point{1, 2});  // 創建一個指向Point結構體的std::unique_ptr并初始化其成員

注意事項

  • 只能創建std::unique_ptrstd::make_unique只能用于創建std::unique_ptr,無法創建std::shared_ptr。對于需要使用std::shared_ptr的情況,應當使用std::make_shared或手動分配。

  • 無法自定義刪除器:與直接使用std::unique_ptr構造函數不同,std::make_unique無法指定自定義的刪除器。如果需要自定義內存釋放方式,需要通過std::unique_ptr的構造函數來實現。

  • 僅適用于單個對象std::make_unique僅用于分配單個對象的內存,并不能用于分配數組。分配數組需要使用std::make_unique替代品std::make_unique_for_overwrite或手動分配。

  • 不支持初始化列表構造函數std::make_unique不支持通過初始化列表構造對象,只能傳遞參數給對象的構造函數來創建對象。

  • 不支持動態數組:使用std::make_unique創建的對象并不支持動態數組,因為std::unique_ptr不支持動態數組的內存釋放。

  • 類類型限制:要使用std::make_unique創建的對象類型,必須是完整的對象類型,不能是不完整類型或抽象類型。

std::shared_timed_mutex and std::shared_lock

在C++14標準中,引入了std::shared_timed_mutexstd::shared_lock,這兩個類分別是用于多線程讀寫操作的共享互斥鎖和共享鎖,提供了更靈活和高效的并發控制機制。

std::shared_timed_mutex

std::shared_timed_mutex是一個支持讀寫操作的共享互斥鎖,允許多個線程同時讀取共享數據,但在寫入操作時會獨占資源。
在這里插入圖片描述

特點:
  • 共享讀取:多個線程可以同時獲取共享鎖(讀取鎖),允許并發讀取數據。

  • 獨占寫入:在寫操作時,會獨占資源,防止并發寫入數據造成數據競爭。

  • 超時支持:支持超時等待功能,可以在一定時間內獲取鎖或放棄操作。

使用std::shared_timed_mutex可以實現多線程讀寫操作的并發控制。以下是std::shared_timed_mutex的基本用法示例:

創建和初始化:

#include <iostream>
#include <thread>
#include <shared_mutex>std::shared_timed_mutex mutex;int shared_data = 0;

讀取操作:

void read_data() {std::shared_lock<std::shared_timed_mutex> lock(mutex);std::cout << "Reading data: " << shared_data << std::endl;
}

寫入操作:

void write_data(int value) {std::unique_lock<std::shared_timed_mutex> lock(mutex);shared_data = value;std::cout << "Writing data: " << shared_data << std::endl;
}

主函數示例:

int main() {// 創建讀線程和寫線程std::thread reader1(read_data);std::thread reader2(read_data);std::thread writer(write_data, 42);// 等待線程執行完畢reader1.join();reader2.join();writer.join();return 0;
}

在上述示例中,通過std::shared_lockstd::unique_lock鎖定std::shared_timed_mutex實現了讀和寫的并發控制。多個讀線程可以同時訪問共享數據shared_data,而寫線程在進行寫操作時會獨占資源,防止讀寫競爭。

std::shared_lock

std::shared_lock是用于管理共享互斥鎖的智能鎖類,它提供了對共享鎖的自動獲取和釋放,簡化了多線程編程中關于共享鎖的操作。
在這里插入圖片描述

特點:
  • 自動加鎖和解鎖std::shared_lock在構造時自動獲取共享鎖,在析構時自動釋放共享鎖,保證鎖的正確使用。

  • 共享鎖支持std::shared_lock可以管理對std::shared_timed_mutex的共享鎖,支持多線程并發讀取數據。

  • 適用于多讀單寫場景:適用于多個線程同時讀取數據,但需要獨占寫入數據的場景,提高了讀操作的并發性能。

std::shared_lock是C++14標準中用于管理共享互斥鎖的智能鎖類,它提供了對共享鎖的自動獲取和釋放,能夠簡化多線程編程中的共享數據訪問操作。以下是使用std::shared_lock的基本示例:

示例代碼:

#include <iostream>
#include <thread>
#include <shared_mutex>std::shared_timed_mutex mutex;
int shared_data = 0;void read_data() {std::shared_lock<std::shared_timed_mutex> lock(mutex);std::cout << "Reading data: " << shared_data << std::endl;
}void write_data(int value) {std::unique_lock<std::shared_timed_mutex> lock(mutex);shared_data = value;std::cout << "Writing data: " << shared_data << std::endl;
}int main() {// 創建讀線程和寫線程std::thread reader1(read_data);std::thread reader2(read_data);std::thread writer(write_data, 42);// 等待線程執行完畢reader1.join();reader2.join();writer.join();return 0;
}
  1. 在主函數中,創建了兩個讀線程reader1reader2,以及一個寫線程writer

  2. read_data()函數中使用std::shared_lock來鎖定std::shared_timed_mutex,實現共享鎖的獲取,允許多個線程同時讀取共享數據shared_data

  3. write_data(int value)函數中使用std::unique_lock來鎖定std::shared_timed_mutex,實現獨占鎖的獲取,確保寫入操作時獨占資源,防止數據競爭。

  4. 主函數中啟動讀線程和寫線程,并通過join()等待線程執行完畢。

  5. 在讀取數據時,通過std::shared_lock獲取共享鎖來讀取共享數據,而在寫入數據時,通過std::unique_lock獲取獨占鎖來寫入數據。

std::integer_sequence

std::integer_sequence是C++14引入的一個模板類,用于表示編譯時整數序列。這個實用的模板類使得編譯時的整數操作(比如索引列表、解包元組等)變得簡單和類型安全。它常常與模板元編程和編譯時計算一起使用,為C++模板提供了強大的編譯時序列處理能力。
在這里插入圖片描述

std::integer_sequence基本概念

std::integer_sequence<T, Ints...>是一個編譯時整數序列的類型,其中T是整數類型(如int, size_t等),而Ints...則是一系列T類型的編譯時常量。

用法示例

假如你想在編譯時生成一個整數序列(例如,0到N-1),可以使用std::make_integer_sequencestd::integer_sequence來實現這一點。這種能力非常方便當你需要基于索引進行模板展開或操作元組時。

示例代碼

下面是一個利用std::integer_sequencestd::make_integer_sequence展開函數參數并打印元組內容的示例:

#include <iostream>
#include <tuple>// 函數模板,用于打印元組中的每個元素
template<typename Tuple, std::size_t... I>
void printTupleImpl(const Tuple& t, std::index_sequence<I...>) {((std::cout << (I == 0 ? "" : ", ") << std::get<I>(t)), ...);
}// 打印元組的主函數模板
template<typename... Args>
void printTuple(const std::tuple<Args...>& t) {printTupleImpl(t, std::make_index_sequence<sizeof...(Args)>{});
}int main() {auto t = std::make_tuple(1, "two", 3.14); // 一個包含不同類型元素的元組std::cout << "Tuple contains: ";printTuple(t); // 打印元組內容std::cout << std::endl;return 0;
}

特性和用途

  1. 編譯時索引生成:利用std::make_integer_sequencestd::make_index_sequence生成一個編譯時索引序列,以便于模板元編程和編譯時算法中進行迭代或索引操作。

  2. 元組訪問與展開:結合std::getstd::index_sequence可以實現編譯時的元組訪問和元素展開,這對于泛型編程中的參數解包特別有用。

  3. 模板元編程std::integer_sequence和相關工具使得在模板元編程中處理整數序列變得更加直觀和類型安全。

通過std::integer_sequence,C++14進一步增強了模板編程的能力,為編譯時的序列操作提供了強大的工具。

std::exchange

std::exchange 是 C++14 標準庫中引入的一項非常實用的功能。它位于 <utility> 頭文件中。這個函數模板允許你將一個變量的值替換為另一個新值,同時返回變量原來的值。這種操作在很多情況下是非常便利的,尤其是在需要更新變量值的同時,又需要保留變量原來的值時。
在這里插入圖片描述

std::exchange 的函數原型

template< class T, class U = T >
T exchange( T& obj, U&& new_value );
  • obj: 是一個將要被新值替換的對象的引用。
  • new_value: 是將要被設置給 obj 的新值。可以是右值引用(采用移動語義),這樣可以避免不必要的復制操作。
  • 返回值:函數返回obj的原始值。

使用示例

下面是一個使用 std::exchange 的簡單示例,展示了如何使用它交換變量的值:

#include <iostream>
#include <utility>
#include <vector>int main() {int old_value = 42;int new_value = 84;// 使用 std::exchange 更新 old_value,同時獲取其原始值int original_value = std::exchange(old_value, new_value);std::cout << "Original value: " << original_value << std::endl;  // 輸出:42std::cout << "New value: " << old_value << std::endl;            // 輸出:84// 也可以用于復雜類型,比如在替換 std::vector 內容時std::vector<int> vec = {1, 2, 3};std::vector<int> new_vec = {4, 5, 6};auto old_vec = std::exchange(vec, std::move(new_vec));// vec 現在 包含 new_vec 的內容,而 new_vec 是空的for (int v : vec) std::cout << v << " ";  // 輸出:4 5 6std::cout << std::endl;return 0;
}

std::quoted

std::quoted 是 C++14 中引入的,位于 <iomanip> 頭文件中的一個實用功能。它提供了一種便捷的方法來對輸入和輸出流進行引用和解引用操作,這在處理包含空格或分隔符的字符串時格外有用。它確保了字符串的完整性,在讀取和寫入文件或處理用戶輸入時特別有用。這個功能的出現簡化了程序員在處理文本數據時需要編寫的引號管理與轉義字符的工具代碼。
在這里插入圖片描述

std::quoted 的基本用法

std::quoted 的主要目的是確保字符串數據在經過輸入輸出操作時,能夠保持它們的字面值,并且正確處理其中的特殊字符。它會自動為字符串添加引號,并且將內部的特殊字符(如引號本身)進行轉義,確保字符串在存儲和傳輸時不會損失信息。

函數簽名

template< class CharT, class Traits, class Allocator >
std::basic_ostream<CharT, Traits>& operator<< (std::basic_ostream<CharT, Traits>& os, const std::basic_string<CharT, Traits, Allocator>& str );template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT, Traits>& operator>> (std::basic_istream<CharT, Traits>& is, std::basic_string<CharT, Traits, Allocator>& str );
  • 第一個函數簽名表示在輸出流中使用std::quoted來寫入字符串。
  • 第二個函數簽名表示在輸入流中使用std::quoted來讀取字符串。

示例代碼

#include <iostream>
#include <sstream>
#include <iomanip> // 導入 std::quotedint main() {std::string input = R"(John Doe "Programmer")";std::stringstream sstream;// 寫入字符串時加上引號和必要的轉義sstream << std::quoted(input);std::cout << sstream.str() << std::endl; // 輸出:"John Doe \"Programmer\""// 從流中讀取字符串時解除引號和轉義std::string output;sstream >> std::quoted(output);std::cout << output << std::endl; // 輸出:John Doe "Programmer"return 0;
}

使用場景

  • 當你需要向文件或其他輸出流寫入字符串,并想保證即使字符串中包含引號或特殊字符也能正確寫入和讀取時,使用 std::quoted
  • 在處理來自用戶的輸入,特別是在需要保留輸入字符串中的空格和引號時。

通過使用 std::quoted,你能夠更簡單地處理文本數據,無需擔心引號管理、轉義符等細節問題。這在讀寫配置文件、處理CSV格式數據、或進行網絡通信時特別有用,因為這些場合下經常會遇到需要精確管理字符串邊界和特殊字符的情況。

and many small improvements to existing library facilities, such as

C++14 不僅引入了一些全新的功能和改進,還對現有庫設施進行了許多小的改進。這些改進提高了標準庫的實用性和靈活性。以下是一些值得注意的改進:

1. 類型推導和 auto 改進

  • 返回類型推導:C++14 改善了函數返回類型的推導能力,使得在編寫函數時,可以省略返回類型,并讓編譯器自動推導。
  • 泛型 Lambda:C++14 允許在 lambda 表達式中使用 auto 關鍵字作為參數類型,從而使 Lambda 表達式具有泛型能力。

2. std::make_unique

C++14 在 <memory> 頭文件中引入了 std::make_unique 函數模板,作為創建 std::unique_ptr 實例的首選方式。這一改進補充了 C++11 中引入的 std::make_shared,使得智能指針的創建更加完整。

3. 數字字面量改進

C++14 引入了對二進制字面量的支持,允許直接用二進制形式表示整數。此外,引入了整型字面量和浮點型字面量的單字符后綴,用于指定更具體的類型。

4. 容器和算法的改進

  • std::cbeginstd::cend:用于獲取容器的 const 迭代器,即使容器本身是非 const 的。
  • 容器訪問函數:如 std::at 函數,增加了對訪問數組元素的安全性。
  • 算法改進:例如,std::copy_n, std::all_of, std::any_of, std::none_of 等標準算法被改進,使其使用起來更加方便。

5. 編譯時整數序列

通過 std::integer_sequencestd::make_integer_sequence 等,C++14 引入了編譯時整數序列的支持,這在模板元編程中非常有用。

6. 定制化點

C++14 引入了定制化點 (customization points),通過定義特殊的自定義命名空間,開發者可以更加靈活地控制 ADL (Argument-Dependent Lookup) 的行為。

7. 其他語言和庫改進

  • 棄用屬性:引入了 [[deprecated]] 屬性,允許標記過時的代碼,提示使用者注意。
  • 特化 std::get<>():對 std::tuplestd::get<>() 函數進行了特化,使得可以通過類型來獲取元素。
  • 著色器語言靜態數據成員:允許著色器語言 (如 OpenGL Shading Language) 著色器和 C++ 代碼共享靜態數據成員。

這些是 C++14 引入的許多小改進中的一部分示例。這些改進的加入,使得 C++ 更加現代化,靈活性和實用性都得到了提升。開發者能夠借助這些新特性和改進,編寫出更簡潔、更高效、更易于維護的代碼。

two-range overloads for some algorithms

在 C++14 標準中,標準庫算法獲得了一項重要的增強:一些算法添加了所謂的“雙范圍重載”版本。這意味著,對于某些算法,你現在可以直接將兩個獨立的范圍當做參數傳入,而不是之前的單個范圍加上目標開始迭代器。這一改進簡化了算法的使用,并使得代碼更易于閱讀和理解。
在這里插入圖片描述

雙范圍算法的使用場景

雙范圍重載在比較兩個容器、復制一個容器到另一個容器、以及在兩個容器之間進行移動、交換時特別有用。它們允許你直接指定源范圍和目標范圍,而不必指定起始和結束迭代器。

主要的雙范圍算法

以下是 C++14 中增加雙范圍重載的一些主要算法:

  • std::equal: 用于比較兩個范圍內的元素是否全部相等。C++14 之前,你需要提供兩個范圍的起始迭代器和第一個范圍的結束迭代器。C++14 允許你直接傳入兩個范圍。
  • std::mismatch: 查找兩個范圍中第一對不匹配的元素。在 C++14 之前,使用此算法同樣需要指定兩個范圍的起始迭代器和第一個范圍的結束迭代器。C++14 使得直接傳入兩個范圍成為可能。
  • std::copy: C++14 為std::copy添加了重載版本,允許兩個范圍作為參數,簡化了從一個容器向另一個容器復制元素的操作。

示例:使用 std::equal 的雙范圍版本

#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> vec1 = {1, 2, 3, 4, 5};std::vector<int> vec2 = {1, 2, 3, 4, 5};// 使用 C++14 中的雙范圍重載bool isEqual = std::equal(vec1.begin(), vec1.end(), vec2.begin(), vec2.end());// 使用 C++14 簡化的雙范圍調用形式bool isEqualSimplified = std::equal(vec1.begin(), vec1.end(), vec2.begin());std::cout << "The vectors are " << (isEqual ? "equal." : "not equal.") << std::endl;std::cout << "Simplified call: The vectors are " << (isEqualSimplified ? "equal." : "not equal.") << std::endl;return 0;
}

type alias versions of type traits

在 C++14 中,對類型特征(type traits)的改進之一是引入了類型別名版本,這些別名提供了更簡潔的語法來訪問類型特征的結果。類型特征是模板元編程中的一種工具,它允許在編譯時對類型進行查詢和操作。在 C++11 中,類型特征通常通過繼承自 std::integral_constant 的模板結構體實現,其結果可以通過::value成員訪問。而 C++14 通過提供類型別名簡化了這個過程,使得獲取類型特征的結果更加直接。
在這里插入圖片描述

類型別名類型特征的優點

相對于 C++11 風格的類型特征,C++14 引入的類型別名版本提供了以下優勢:

  • 簡潔的語法:不需要通過 ::value::type 來訪問結果,可以直接使用類型別名得到想要的結果。
  • 提高代碼的可讀性:代碼更為簡潔,意圖更加明顯,提高了代碼的可讀性和易維護性。

示例

比較 C++11 和 C++14 在使用類型特征時的不同。

C++11 風格
#include <type_traits>int main() {// 使用C++11風格的類型判斷static_assert(std::is_integral<int>::value, "int is an integral type");// 獲取添加const修飾符后的類型typedef std::add_const<int>::type MyConstIntType;
}
C++14 風格
#include <type_traits>int main() {// 使用C++14風格的類型別名static_assert(std::is_integral_v<int>, "int is an integral type"); // 注意使用_v后綴// 使用類型別名獲取添加const修飾符后的類型using MyConstIntType = std::add_const_t<int>; // 注意使用_t后綴
}

主要類型別名特征

C++14 為許多常用的類型特征引入了類型別名,這里列舉一些例子:

  • 類型屬性:例如 std::is_integral_v<T>,直接獲得布爾值結果,而不是 std::is_integral<T>::value
  • 類型修改器:例如 std::add_const_t<T>,得到修改后的類型,而不是 std::add_const<T>::type
  • 類型關系:例如 std::is_same_v<T, U>,直接得到比較結果,而不是 std::is_same<T, U>::value

user-defined literals for basic_string, duration and complex

C++14 中為 std::basic_stringstd::chrono::durationstd::complex 引入了用戶自定義字面量(User-Defined Literals, UDL),這是對 C++11 中用戶自定義字面量功能的擴展。用戶自定義字面量允許字面值直接定義自己的處理方式,使得代碼更加清晰、直觀。

std::basic_string 的用戶自定義字面量

在這里插入圖片描述

在 C++14 中,通過在字符串字面值后添加 s 后綴,可以直接創建 std::string 實例。這一功能由頭文件 <string> 提供。

#include <iostream>
#include <string>using namespace std::string_literals;int main() {// 使用用戶自定義字面量創建 std::stringauto myString = "Hello, world!"s;std::cout << myString << std::endl;return 0;
}

這樣的用戶自定義字面量不僅適用于 std::string,也適用于 std::wstringstd::u16stringstd::u32string,分別通過在字面值后添加 wss16s32 后綴來創建。

std::chrono::duration 的用戶自定義字面量

C++14 對 std::chrono 庫進行了增強,引入了表示時間的用戶自定義字面量,使得表示特定時間間隔變得更加直觀。這些字面量定義在頭文件 <chrono> 中。
在這里插入圖片描述

#include <iostream>
#include <chrono>using namespace std::chrono_literals;int main() {auto oneSecond = 1s;  // std::chrono::seconds 類型auto halfAMinute = 30s;  // 同樣是 std::chrono::seconds 類型auto oneDay = 24h;  // std::chrono::hours 類型std::cout << "One day has " << oneDay.count() << " hours." << std::endl;return 0;
}

std::complex 的用戶自定義字面量

C++14 也為復數類型 std::complex 引入了用戶自定義字面量。通過在整數或浮點字面值后添加 iifil 后綴,可以創建 std::complex 類型的實例,表示復數。這一功能由頭文件 <complex> 提供。

#include <iostream>
#include <complex>using namespace std::complex_literals;int main() {auto myComplex = 3.0 + 4i;  // 創建 std::complex<double> 實例std::cout << "Real part: " << myComplex.real() << ", Imaginary part: " << myComplex.imag() << std::endl;return 0;
}

【大廠面經、學習筆記、實戰項目、大綱路線、講解視頻 領取文檔】C++校招實習、社招、面試題
https://docs.qq.com/doc/DR2N4d25LRG1leU9Q

C/C++Linux服務器開發/高級架構師學習資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等)領取君羊739729163
合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35184.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35184.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35184.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決Vue+Vite打包后Leaflet的marker圖標不顯示的問題

前言 用Leaflet寫關于WebGIS的開發&#xff0c;用Vite或者webpack打包&#xff0c;打包后會找不到圖標&#xff0c;如下所示。 直言的說&#xff0c;筆者去網上搜了搜&#xff0c;其實收到一個比較好是答案。網址如下。 &#xff08;完美解決~&#xff09;關于VueLeaflet添加…

eslint 與 prettier 的一些常見的配置項(很詳細)

目錄 1、eslint 常見配置項&#xff08;語法規范&#xff09; 2、 prettier 常見的配置項&#xff08;格式規范&#xff09; 代碼規范相關內容看小編的該文章&#xff0c;獲取對你有更好的幫助 vsCode代碼格式化&#xff08;理解eslint、vetur、prettier&#xff0c;實現格式…

IDEA啟動報錯:Abnormal build process termination...

一、問題描述 因為項目需要&#xff0c;同時打開了兩個idea&#xff0c;突然發現一個啟動的時候報錯&#xff0c;有點莫名其妙&#xff0c;剛還好好的&#xff0c;為啥就不能用了&#xff0c;一頓百度找方法&#xff0c;試了各種方法&#xff0c;像重新安裝jdk、重啟系統發現都…

TensorFlow開源項目

歡迎來到 Papicatch的博客 文章目錄 &#x1f349;TensorFlow介紹 &#x1f349;主要特點和功能 &#x1f348;多語言支持 &#x1f348;靈活的架構 &#x1f348;分布式訓練 &#x1f348;跨平臺部署 &#x1f348;強大的工具鏈 &#x1f348;豐富的社區和生態系統 &a…

c++基本數據類型和計算(一)習題講解

1.【單選題】以下說法正確的是? A. unsigned 類型的值 最大為0xFFFFFFFF B. float類型的值大約有15位精度 C.bool類型占用4個字節 解析&#xff1a; 選項A&#xff1a;unsigned 類型的值 最大為 4個字節&#xff0c;正確。選項B&#xff1a; 因為float類型的值是單精度的浮…

Vue3基礎使用

目錄 一、創建Vue3工程 (一)、cli (二)、vite 二、常用Composition API (一)、setup函數 (二)、ref函數 (三)、reactive函數 (四)、setup注意事項 (五)、計算屬性 (六)、watch (七)、watchEffect函數 (八)、生命周期 1、以配置項的形式使用生命周期鉤子 2、組合式…

kafka-簡單代碼實現生產者消費者

生產者代碼&#xff1a; package com.kafka.test;import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.seriali…

【機器學習-10】 | Scikit-Learn工具包進階指南:Scikit-Learn工具包之支持向量機模塊研究

&#x1f3a9; 歡迎來到技術探索的奇幻世界&#x1f468;?&#x1f4bb; &#x1f4dc; 個人主頁&#xff1a;一倫明悅-CSDN博客 ?&#x1f3fb; 作者簡介&#xff1a; C軟件開發、Python機器學習愛好者 &#x1f5e3;? 互動與支持&#xff1a;&#x1f4ac;評論 &…

高考填報志愿攻略,5個步驟選專業和院校

在高考完畢出成績的時候&#xff0c;很多人會陷入迷茫中&#xff0c;好像努力了這么多年&#xff0c;卻不知道怎么規劃好未來。怎么填報志愿合適&#xff1f;在填報志愿方面有幾個內容需要弄清楚&#xff0c;按部就班就能找到方向&#xff0c;一起來了解一下正確的步驟吧。 第…

入局AI手機 蘋果公布Apple Intelligence

日前&#xff0c;蘋果WWDC 2024如期召開。在這持續1個小時44分鐘的開發者大會上&#xff0c;蘋果在前一個小時里更新了iOS、iPadOS、MacOS等操作系統&#xff0c;而且還首次更新了visionOS。余下的時間全部留給了蘋果的“AI大禮包”——Apple Intelligence&#xff08;蘋果智能…

請說明Thread類中run和start的區別,從方法的區別,及運行結果的區別分別說明

方法本身的區別 start() 方法&#xff1a; run()方法是Thread類的一個普通方法&#xff0c;它包含了線程要執行的代碼。當你直接調用一個線程的run()方法&#xff08;如myThread.run()&#xff09;&#xff0c;你實際上是在當前線程&#xff08;通常是主線程&#xff09;中執行…

PointCloudLib-濾波模塊(Filtering)-使用參數化模型投影點

在本教程中,我們將學習如何將點投影到參數化模型上 (例如,平面、球體等)。參數模型通過一組 系數 – 在平面的情況下,通過其方程:ax + by + cz + d = 0。 代碼 #include <iostream> #include <pcl/point_cloud.h> // for PointCloud #include <pcl/point…

mysql是什么

mysql是什么 是DBMS軟件系統&#xff0c;并不是一個數據庫&#xff0c;管理數據庫 DBMS相當于用戶和數據庫之間的橋梁&#xff0c;有超過300種不同的dbms系統 mysql是關系型數據庫&#xff0c;關系型數據庫存儲模型很想excel&#xff0c;用行和列組織數據 sql是一門編程語言…

關于ip地址的網頁無法訪問navigator的gpu、媒體、藍牙等設備的解決方法

在使用threejs的WebGPURenderer渲染器時&#xff0c;發現localhost以及127.0.0.1才能訪問到navigator.gpu&#xff0c;直接使用ip會變成undefined,原因是為了用戶的隱私安全&#xff0c;只能在安全的上下文中使用&#xff0c;非安全的上下文就會是undefined&#xff0c;安全上下…

谷歌云(GCP)4門1453元最熱門證書限時免費考

谷歌云(GCP)最新活動&#xff0c;完成免費官方課程&#xff0c;送4門最熱門考試免費考試券1張(每張價值200刀/1453元)&#xff0c;這4門也包括最近大熱的AI/ML考試&#xff0c;非常值得學習和參加&#xff0c;活動7/17截止 谷歌云是全球最火的三大云計算廠商(前兩名AWS, Azure…

MySQL索引優化解決方案--索引失效(3)

索引失效情況 最佳左前綴法則&#xff1a;如果索引了多列&#xff0c;要遵循最左前綴法則&#xff0c;指的是查詢從索引的最左前列開始并且不跳過索引中的列。不在索引列上做任何計算、函數操作&#xff0c;會導致索引失效而轉向全表掃描存儲引擎不能使用索引中范圍條件右邊的…

【Linux】進程信號_1

文章目錄 八、進程信號1.信號 未完待續 八、進程信號 1.信號 信號和信號量之間沒有任何關系。信號是Linux系統提供的讓用戶/進程給其他進程發送異步信息的一種方式。 常見信號&#xff1a; 當信號產生時&#xff0c;可選的處理方式有三種&#xff1a;①忽略此信號。②執行該…

小程序注冊

【 一 】小程序注冊 微信公眾平臺 https://mp.weixin.qq.com/ https://mp.weixin.qq.com/注冊 郵箱激活 小程序賬戶注冊 微信小程序配置 微信小程序開發流程 添加項目成員 【 二 】云服務 lass 基礎設施服務&#xff08;組裝機&#xff09; 你買了一大堆的電腦配件&#x…

AI早班車2024.6.25

全球AI新聞速遞 1.高通&#xff1a;開放 AI 模型&#xff0c;幫助開發者打造驍龍 X Elite 平臺智能應用。 2.OpenAI&#xff1a;收購數據庫分析公司Rockset。 3.大眾海外版車型支持 ChatGPT。 4.樂聚夸父人形機器人&#xff0c;搭載華為云盤古具身智能大模型。 5.微軟正努力…