C++ 模板基础

最后更新: 2021-05-03 19:04:55 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

模板是一个由类型、常量值、模板和参数包参数化的声明族。特化是在 C++ 名称查找、类型检查、重载决议和约束规则下形成的;模板不是文本替换。

模板参数 #

类型参数接受类型,常量模板参数接受结构化常量值,模板模板参数接受兼容的模板。默认值用于提供省略的实参。参数包表示零个或多个参数或实参。

cpp
template <class T, std::size_t N = 16>
struct Buffer;

template <auto Value>
struct Constant;

template <template <class...> class Container, class T>
using one_element_container = Container<T>;

template <class... Ts>
struct TypeList {};

类模板或别名模板可以具有类型参数、常量参数、模板参数和参数包。函数模板还支持推导:出现在可推导参数位置的实参会从调用实参中推断,而不可推导参数必须由调用方提供,或从其他位置获得。

cpp
template <class T>
T maximum(T left, T right);

auto a = maximum(1, 2);       // T is int
auto b = maximum<double>(1, 2.5);

显式模板实参位于普通调用实参之前。推导不会使用函数返回类型,因为调用结果可能被丢弃,而且重载决议需要在结果类型已知之前获得候选类型。

模板类别和 CTAD #

函数模板、类模板、变量模板、别名模板和成员模板具有不同的实例化规则。

cpp
#include <type_traits>

template <class T> T identity(T value) { return value; } // function
template <class T> struct Box { T value; };               // class
template <class T> inline constexpr bool is_box = false;  // variable
template <class T> using remove_cvref_t =                 // alias
    std::remove_cvref_t<T>;

struct Store {
    template <class T> void put(T&& value);               // member
};

类模板实参推导(CTAD)根据构造函数、聚合推导候选项或用户定义的推导指引来选择类模板实参。当使用不带显式实参的类模板名称时,CTAD 会生效;它不适用于函数模板。

cpp
template <class T>
struct Pair { T first; T second; };

template <class T, class U>
Pair(T, U) -> Pair<std::common_type_t<T, U>>;

Pair values{1, 2}; // Pair<int> through the deduction guide

当构造函数参数类型无法表达预期的存储类型时,应编写推导指引。如果明确写出类型能够更清晰地表达所有权、单位或窄化策略,则不要在 API 边界依赖 CTAD。

实例化和可见性 #

当需要某个特化时,会发生隐式实例化,但须遵守实例化点规则。相关模板定义必须在该点可达,这也是函数和类模板定义通常位于头文件中的原因。

显式实例化定义会生成一个特化;extern template声明会抑制翻译单元中的隐式实例化,而该翻译单元可以使用其他位置提供的实例化。

cpp
// widget.hpp
template <class T>
class Widget {
public:
    void draw();
};

extern template class Widget<int>;

// widget.cc, after the definition is visible
template <class T>
void Widget<T>::draw() {}

template class Widget<int>;

显式实例化是一种构建时控制手段,不能替代使每个所需特化都有效。确保声明在其使用之前可见,并在编译器必须进行实例化的所有位置保持模板定义可见。

评论

在 GitHub 上阅读或评论(发表评论需要登录)