从 C++ 基础到掌握 — 第 13 集
使用模板减少不同类型的重复代码
该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。
有时,查找物品 ID 的函数和查找怪物 ID 的函数具有几乎相同的形状。 如果只是数据类型不同而行为相同,则可以使用模板创建通用规则,而不是复制代码。
函数模板
让我们首先创建一个返回两个值中较大者的函数。
template <typename T>
T Max(const T& a, const T& b)
{
return a < b ? b : a;
}
int highLevel = Max(10, 20);
float highDamage = Max(12.5f, 8.0f);
T是调用函数时改变实际类型的地方。 编译器Max<int>和Max<float>根据需要创建每个函数。
但Max(10, 3.5f)如果传递不同的类型,编译会失败,因为无法确定一个T。 您必须显式匹配分别接受这两种类型的类型或设计模板。
类模板
如果你想对多种类型使用相同大小的槽,你也可以创建一个类作为模板。
template <typename T, std::size_t Size>
class Inventory
{
public:
T& At(std::size_t index)
{
return slots.at(index);
}
const T& At(std::size_t index) const
{
return slots.at(index);
}
private:
std::array<T, Size> slots{};
};
Inventory<Item, 20> itemInventory;
Inventory<Skill, 8> skillInventory;
T 是类型,Size 是编译时确定的值。 std::array由于大小在运行时不会改变,因此有利于表达固定槽。
模板和头文件
常规函数可以在标头中声明并在 cpp 中定义。 但是,模板的定义在编译器为实际类型创建代码时必须可见。
// Inventory.h
template <typename T>
class Inventory
{
public:
void Add(const T& value)
{
values.push_back(value);
}
private:
std::vector<T> values;
};
所以模板定义通常写在头部。 如果只将声明放在 header 中,而将定义隐藏在 cpp 中,则可能会因找不到特定类型的代码而出现链接错误。
使用模板的标准
如果代码类型不同但含义相同,则模板可以减少重复。 相反,如果将具有不同操作和职责的代码强制放入单个模板中,则条件语句和特殊处理就会增加。
模板并不是泛化所有代码的函数。 最好将其视为一种工具,可以安全地将相同的规则应用于多种类型,并防止在编译阶段出现错误的组合。