成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

掌握C++模板的藝術:類型參數、默認值和自動推導

開發 前端
在 Grid 示例中,Grid 模板有一個模板參數:存儲在網格中的類型。編寫類模板時,您需要在尖括號內指定參數列表。

一、模板參數

1.類型模板參數

在 Grid 示例中,Grid 模板有一個模板參數:存儲在網格中的類型。編寫類模板時,您需要在尖括號內指定參數列表,例如:

template <typename T>

這個參數列表類似于函數或方法中的參數列表。與函數和方法一樣,你可以編寫具有任意多個模板參數的類。此外,這些參數不必是類型,它們可以有默認值。

2.非類型模板參數

非類型參數是普通參數,如整數和指針——這類參數你可能已經在函數和方法中很熟悉了。然而,非類型模板參數只能是整型(char、int、long 等)、枚舉類型、指針、引用、std::nullptr_t、auto、auto& 和 auto*。C++20 還允許浮點類型和類類型的非類型模板參數。后者有很多限制,在本文中不再詳細討論。

在 Grid 類模板中,你可以使用非類型模板參數來指定網格的高度和寬度,而不是在構造函數中指定。在模板列表中指定非類型參數而不是在構造函數中指定的主要優點是這些值在代碼編譯之前就已知。回想一下,編譯器通過在編譯之前替換模板參數來生成模板實例的代碼。因此,你可以在實現中使用普通的二維數組,而不是動態調整大小的向量數組。以下是帶有更改的新類定義:

export template <typename T, size_t WIDTH, size_t HEIGHT>
class Grid {
public:
    Grid() = default;
    virtual ~Grid() = default;
    // 明確默認復制構造函數和賦值運算符。
    Grid(const Grid& src) = default;
    Grid& operator=(const Grid& rhs) = default;

    std::optional<T>& at(size_t x, size_t y);
    const std::optional<T>& at(size_t x, size_t y) const;

    size_t getHeight() const { return HEIGHT; }
    size_t getWidth() const { return WIDTH; }

private:
    void verifyCoordinate(size_t x, size_t y) const;
    std::optional<T> m_cells[WIDTH][HEIGHT];
};

注意,模板參數列表需要三個參數:存儲在網格中的對象類型,以及網格的寬度和高度。寬度和高度用于創建存儲對象的二維數組。下面是類方法的定義:

// 類方法定義
template <typename T, size_t WIDTH, size_t HEIGHT>
void Grid<T, WIDTH, HEIGHT>::verifyCoordinate(size_t x, size_t y) const {
    if (x >= WIDTH) {
        throw std::out_of_range { std::format("{} must be less than {}.", x, WIDTH) };
    }
    if (y >= HEIGHT) {
        throw std::out_of_range { std::format("{} must be less than {}.", y, HEIGHT) };
    }
}

template <typename T, size_t WIDTH, size_t HEIGHT>
const std::optional<T>& Grid<T, WIDTH, HEIGHT>::at(size_t x, size_t y) const {
    verifyCoordinate(x, y);
    return m_cells[x][y];
}

template <typename T, size_t WIDTH, size_t HEIGHT>
std::optional<T>& Grid<T, WIDTH, HEIGHT>::at(size_t x, size_t y) {
    return const_cast<std::optional<T>&>(std::as_const(*this).at(x, y));
}

注意,之前你在哪里指定了 Grid<T>,現在你必須指定 Grid<T, WIDTH, HEIGHT> 來指定三個模板參數。你可以這樣實例化并使用這個模板:

Grid<int,

 10, 10> myGrid;
Grid<int, 10, 10> anotherGrid;
myGrid.at(2, 3) = 42;
anotherGrid = myGrid;
cout << anotherGrid.at(2, 3).value_or(0);

這段代碼看起來很棒,但不幸的是,存在比你最初預期的更多限制。首先,你不能使用非常量整數來指定高度或寬度。以下代碼無法編譯:

size_t height { 10 };
Grid<int, 10, height> testGrid; // 無法編譯

然而,如果你將高度定義為常量,則可以編譯:

const size_t height { 10 };
Grid<int, 10, height> testGrid; // 可編譯并工作

具有正確返回類型的 constexpr 函數也可以工作。例如,如果你有一個返回 size_t 的 constexpr 函數,你可以用它來初始化高度模板參數:

constexpr size_t getHeight() { return 10; }
...
Grid<double, 2, getHeight()> myDoubleGrid;

第二個限制可能更重要。現在寬度和高度是模板參數,它們是每個網格類型的一部分。這意味著 Grid<int,10,10> 和 Grid<int,10,11> 是兩種不同的類型。你不能將一種類型的對象賦值給另一種類型的對象,也不能將一種類型的變量傳遞給期望另一種類型變量的函數或方法。

注意:非類型模板參數成為實例化對象類型規范的一部分。

二、類模板參數的默認值

設置高度和寬度的默認值

如果您繼續使用高度和寬度作為模板參數的方法,您可能想為 Grid<T> 類構造函數中之前的高度和寬度非類型模板參數提供默認值。C++ 允許您使用類似的語法為模板參數提供默認值。同時,您也可以為 T 類型參數提供默認值。下面是類定義:

export template <typename T = int, size_t WIDTH = 10, size_t HEIGHT = 10>
class Grid {
    // 其余部分與之前版本相同
};

在方法定義的模板規范中,您不需要為 T、WIDTH 和 HEIGHT 指定默認值。例如,這是 at() 方法的實現:

template <typename T, size_t WIDTH, size_t HEIGHT>
const std::optional<T>& Grid<T, WIDTH, HEIGHT>::at(size_t x, size_t y) const {
    verifyCoordinate(x, y);
    return m_cells[x][y];
}

現在,您可以在沒有任何模板參數的情況下實例化 Grid,只需指定元素類型,元素類型和寬度,或元素類型、寬度和高度:

Grid<> myIntGrid;
Grid<int> myGrid;
Grid<int, 5> anotherGrid;
Grid<int, 5, 5> aFourthGrid;

請注意,如果您不指定任何類模板參數,您仍然需要指定一組空的尖括號。例如,以下代碼無法編譯!

Grid myIntGrid;

類模板參數列表中默認參數的規則與函數或方法相同;也就是說,您可以從右邊開始為參數提供默認值。

三、類模板參數推導(CTAD)

1.自動推導模板參數

類模板參數推導允許編譯器自動從傳遞給類模板構造函數的參數推導出模板參數。例如,標準庫中有一個名為 std::pair 的類模板,在 <utility> 中定義,并在第1章中介紹。pair 存儲兩個可能不同類型的值,通常需要指定為模板參數。例如:

pair<int, double> pair1 { 1, 2.3 };

為了避免編寫模板參數,可以使用一個名為 std::make_pair() 的輔助函數模板。編寫自己的函數模板的細節將在本章后面討論。函數模板一直支持基于傳遞給函數模板的參數自動推導模板參數。因此,make_pair() 能夠根據傳遞給它的值自動推導出模板類型參數。例如,編譯器為以下調用推導出 pair<int, double>:

auto pair2 { make_pair(1, 2.3) };

使用類模板參數推導(CTAD),不再需要這樣的輔助函數模板。編譯器現在會根據傳遞給構造函數的參數自動推導出模板類型參數。對于 pair 類模板,您可以簡單地編寫以下代碼:

pair pair3 { 1, 2.3 }; // pair3 的類型為 pair<int, double>

當然,這僅在類模板的所有模板參數要么具有默認值,要么用作構造函數中的參數,從而可以推導出來時才有效。請注意,CTAD 要求有一個初始化器才能工作。以下是非法的:

pair pair4;

許多標準庫類支持 CTAD,例如 vector、array 等。

注意:這種類型推導對 std::unique_ptr 和 shared_ptr 無效。您向它們的構造函數傳遞 T*,這意味著編譯器必須在推導 <T> 或 <T[]> 之間選擇,如果選錯了就會很危險。因此,請記住,對于 unique_ptr 和 shared_ptr,您需要繼續使用 make_unique() 和 make_shared()。

2.用戶定義的推導指南

您也可以編寫自己的用戶定義推導指南來幫助編譯器。這些指南允許您編寫模板參數如何被推導的規則。這是一個高級主題,所以不會詳細討論,但會給出一個示例來展示它們的強大功能。假設您有以下 SpreadsheetCell 類模板:

template <typename T>
class SpreadsheetCell {
public:
    SpreadsheetCell(T t) : m_content { move(t) } { }
    const T& getContent() const { return m_content; }

private:
    T m_content;
};

使用自動模板參數推導,您可以創建一個 std::string 類型的 SpreadsheetCell:

string myString { "Hello World!" };
SpreadsheetCell cell { myString };

然而,如果您將 const char 傳遞給 SpreadsheetCell 構造函數,則類型 T 被推導為 const char,這不是您想要的!您可以創建以下用戶定義的推導指南,當向構造函數傳遞 const char* 作為參數時,使其將 T 推導為 std::string:

SpreadsheetCell(const char*) -> SpreadsheetCell<std::string>;

這個指南必須在類定義之外但在與 SpreadsheetCell 類相同的命名空間內定義。通用語法如下。explicit 關鍵字是可選的,其行為與構造函數的 explicit 相同。通常,這樣的推導指南也是模板。

explicit TemplateName(Parameters) -> DeducedTemplate;
責任編輯:趙寧寧 來源: coding日記
相關推薦

2024-01-17 23:10:59

C++函數模板開發

2023-09-25 12:12:01

C++自動返回

2024-02-19 08:11:40

C++編程尾返回類型推導

2010-02-03 17:42:33

C++模板參數

2010-02-04 14:22:25

C++函數模板非類型參

2010-02-04 14:01:43

C++非類型類模板參數

2024-12-19 11:30:00

C++17CTAD代碼

2010-09-28 10:23:36

SQL修改字段

2022-11-14 07:08:23

Python函數參數

2023-09-01 21:20:06

授權委派KPI

2024-04-29 07:48:04

C++FinalOverride

2012-08-01 09:50:11

交互設計UI設計

2009-09-11 12:31:15

C# WinForm控設置默認值

2009-08-31 14:34:46

C#值類型C#結構類型

2010-01-08 16:52:57

C++和C#

2010-01-28 13:45:06

C++數組

2024-01-29 01:30:00

函數C++編程

2016-12-20 16:35:52

NodeJSC++類型轉換

2016-12-07 11:23:52

NodeJSC++

2011-04-11 10:09:20

委托反饋C++
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 视频在线h| 黄片毛片在线观看 | 日产精品久久久一区二区福利 | 91精品国产综合久久久久 | 综合久| 中文字幕成人在线 | 亚洲人成一区二区三区性色 | 99热碰| 懂色av一区二区三区在线播放 | 精品在线看 | 另类在线| 日本在线精品视频 | 久久久久一区二区三区 | 成人免费视频 | ww亚洲ww亚在线观看 | 91免费看片 | 欧美精品中文字幕久久二区 | 中文字幕一区二区三区精彩视频 | 欧美影院久久 | 夜夜摸天天操 | 国产欧美日韩综合精品一区二区 | 天天综合网7799精品 | 亚洲综合大片69999 | 亚洲国产一区在线 | 国产午夜视频 | 亚洲首页| 欧美综合国产精品久久丁香 | 亚洲美乳中文字幕 | 亚洲成年人免费网站 | 日本人做爰大片免费观看一老师 | 日本成人区 | 日韩成人在线视频 | 欧美成年黄网站色视频 | 亚洲一区二区在线视频 | 91精品国产91久久久久福利 | 一区视频在线免费观看 | 黄色大片免费观看 | 中文字幕国产 | 日本一区高清 | 91在线看片 | 97精品久久 |