模板參數自動推導
在C++17之前,類模板構造器的模板參數是不能像函數模板的模板參數那樣被自動推導的,比如我們無法寫
std::pair a{1, "a"s}; // C++17
而只能寫
std::pair<int, string> a{1, "a"s}; // C++14
為了彌補這一缺陷,標准庫為我們提供了 std::make_pair 函數,通過函數模板的模板參數自動推導的功能,
免去我們在構造 pair 時寫模板參數的麻煩。
auto a = std::make_pair(1, "a"s); // C++14
// 相當於
// std::pair<int, string> a = std::make_pair<int, string>(1, string("a"));
// 這里編譯器根據 std::make_pair 所帶參數的類型,自動推導出了函數模板的參數。
這個解決方案其實並不太理想,這是因為:
- 我們需要記住 make_pair, make_tuple 這類用於構造模板類的慣用法。
- 有些 make_XXX 函數在功能上並不等價於類模板的構造器,比如 make_shared 等等。
在C++17中,這個問題得到了解決,類模板構造器的模板參數同樣能夠被自動推導
std::pair a{1, "a"s}; // C++17
// 相當於
// std::pair<int, string> a{1, "a"s};
// 和函數模板一樣,這里編譯器根據 std::pair 構造器所帶參數類型,自動推導出了構造器模板的參數。
由此我們不再需要 std::make_pair 之類的輔助函數了。
示例
#include <iostream>
#include <vector>
#include <functional>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
vector a = {1, 2, 3}; // C++17
// vector<int> a = {1, 2, 3}; // C++14
function f = [](int a){return a + 1;}; // C++17
// function<int(int)> f = [](int a){return a + 1;}; // C++14
tuple t{1, 2,5, "a"s}; // C++17
// tuple<int, double, string> t{1, 2,5, "a"s}; // C++14
// auto t = make_tuple(1, 2,5, "a"s); // C++14
sort(a.begin(), a.end(), greater{}); // C++17
// sort(a.begin(), a.end(), greater<>{}); // C++14
// sort(a.begin(), a.end(), greater<int>{}); // C++11
// map m = {{1, "a"s}, {2, "b"s}}; // {1, "a"s} 這種使用大括號的初始化列表沒有類型
// 所以編譯器無法自動推導 map 類模板的參數類型
map m = {pair{1, "a"s}, {2, "b"s}}; // C++17
// map<int, string> m = {{1, "a"s}, {2, "b"s}}; // C++14
}
以下內容來自視頻 Class Template Argument Deduction
自定義類模板中的應用
template<typename T>
struct Container
{
Container(T* ptr) {} // 構造器 1
Container(T& v) {} // 構造器 2
Container(T const& v) {} // 構造器 3
template<typename D>
Container(T* ptr, D& deleter) {} // 構造器 4
};
struct Deleter {};
int main()
{
Container c{(int*)0}; // 調用構造器 1
int x; Container c2{x}; // 調用構造器 2
Container c3{0}; // 調用構造器 3
Deleter d;
Container c4{(int*)0, d}; // 調用構造器 4
// 以上編譯器自動推導的結果都是 Container<int>
}
Automatic deduction guides(自動推斷向導)
有些情況下,編譯器無法對類模板的參數做出自動推導,比如下面這種模板參數類型是個嵌套類型的情況。
此時我們需要添加自動推斷向導來幫助編譯器來進行自動推導。
自動推斷向導形式如下:
類模板名(參數列表) -> 類模板id
template<typename T>
struct Traits { using type = T; };
template<typename T>
struct Container
{
// 參數類型是嵌套類型,無法進行自動推導
Container(typename Traits<T>::type v) {}
};
// 自動推斷向導
template<typename T>
Container(T) -> Container<T>;
int main()
{
Container c(0); // 編譯器自動推導的結果是 Container<int>
}
