自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

掌握C++模板的藝術(shù):類型參數(shù)、默認值和自動推導(dǎo)

開發(fā) 前端
在 Grid 示例中,Grid 模板有一個模板參數(shù):存儲在網(wǎng)格中的類型。編寫類模板時,您需要在尖括號內(nèi)指定參數(shù)列表。

一、模板參數(shù)

1.類型模板參數(shù)

在 Grid 示例中,Grid 模板有一個模板參數(shù):存儲在網(wǎng)格中的類型。編寫類模板時,您需要在尖括號內(nèi)指定參數(shù)列表,例如:

template <typename T>

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

2.非類型模板參數(shù)

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

在 Grid 類模板中,你可以使用非類型模板參數(shù)來指定網(wǎng)格的高度和寬度,而不是在構(gòu)造函數(shù)中指定。在模板列表中指定非類型參數(shù)而不是在構(gòu)造函數(shù)中指定的主要優(yōu)點是這些值在代碼編譯之前就已知?;叵胍幌?,編譯器通過在編譯之前替換模板參數(shù)來生成模板實例的代碼。因此,你可以在實現(xiàn)中使用普通的二維數(shù)組,而不是動態(tài)調(diào)整大小的向量數(shù)組。以下是帶有更改的新類定義:

export template <typename T, size_t WIDTH, size_t HEIGHT>
class Grid {
public:
    Grid() = default;
    virtual ~Grid() = default;
    // 明確默認復(fù)制構(gòu)造函數(shù)和賦值運算符。
    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];
};

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

// 類方法定義
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>,現(xiàn)在你必須指定 Grid<T, WIDTH, HEIGHT> 來指定三個模板參數(shù)。你可以這樣實例化并使用這個模板:

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);

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

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

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

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

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

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

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

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

二、類模板參數(shù)的默認值

設(shè)置高度和寬度的默認值

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

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

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

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];
}

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

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

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

Grid myIntGrid;

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

三、類模板參數(shù)推導(dǎo)(CTAD)

1.自動推導(dǎo)模板參數(shù)

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

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

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

auto pair2 { make_pair(1, 2.3) };

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

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

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

pair pair4;

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

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

2.用戶定義的推導(dǎo)指南

您也可以編寫自己的用戶定義推導(dǎo)指南來幫助編譯器。這些指南允許您編寫模板參數(shù)如何被推導(dǎo)的規(guī)則。這是一個高級主題,所以不會詳細討論,但會給出一個示例來展示它們的強大功能。假設(shè)您有以下 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;
};

使用自動模板參數(shù)推導(dǎo),您可以創(chuàng)建一個 std::string 類型的 SpreadsheetCell:

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

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

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

這個指南必須在類定義之外但在與 SpreadsheetCell 類相同的命名空間內(nèi)定義。通用語法如下。explicit 關(guān)鍵字是可選的,其行為與構(gòu)造函數(shù)的 explicit 相同。通常,這樣的推導(dǎo)指南也是模板。

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

2024-01-17 23:10:59

C++函數(shù)模板開發(fā)

2023-09-25 12:12:01

C++自動返回

2024-02-19 08:11:40

C++編程尾返回類型推導(dǎo)

2010-02-03 17:42:33

C++模板參數(shù)

2010-02-04 14:22:25

C++函數(shù)模板非類型參

2010-02-04 14:01:43

C++非類型類模板參數(shù)

2024-12-19 11:30:00

C++17CTAD代碼

2010-09-28 10:23:36

SQL修改字段

2022-11-14 07:08:23

Python函數(shù)參數(shù)

2009-09-11 12:31:15

C# WinForm控設(shè)置默認值

2012-08-01 09:50:11

交互設(shè)計UI設(shè)計

2009-08-31 14:34:46

C#值類型C#結(jié)構(gòu)類型

2024-04-29 07:48:04

C++FinalOverride

2010-01-08 16:52:57

C++和C#

2023-09-01 21:20:06

授權(quán)委派KPI

2024-01-29 01:30:00

函數(shù)C++編程

2016-12-20 16:35:52

NodeJSC++類型轉(zhuǎn)換

2010-01-28 13:45:06

C++數(shù)組

2021-02-25 13:40:17

MySQL數(shù)據(jù)庫默認值

2016-12-07 11:23:52

NodeJSC++
點贊
收藏

51CTO技術(shù)棧公眾號