【C/C++基础进阶系列】C/C++ 泛型 -- 类模板(一)
发布日期:2021-05-07 20:53:16 浏览次数:22 分类:精选文章

本文共 2910 字,大约阅读时间需要 9 分钟。

C++ 类模板基础进阶系列

类模板基础与实例化

类模板是一种强大的编程工具,能够通过模板参数的泛化和特化,减少代码的冗余,提高代码的可维护性和可扩展性。在 C++ 中,类模板的核心思想是通过定义模板参数,创建适用于不同数据类型的类实例。

模板参数的定义与使用

模板参数通常用 template <typename T> 的形式定义,T 表示一个模板参数,可以是任意的数据类型。例如,以下是一个简单的类模板定义:

#include 
using namespace std;
namespace _nmsp1 {
template
class myvector {
public:
typedef T* myiterator; // 迭代器类型定义
myvector();
myvector(T tmpt) {}
myvector& operator=(const myvector&);
void myfunc() { cout << "myfunc()被调用" << endl; }
static void mystaticfunc() { cout << "mystaticfunc()被调用" << endl; }
myiterator mybegin();
myiterator myend();
};
template
myvector
::myvector() {}
}

类模板的实例化

类模板的实例化发生在以下两种情况:

  • 显式实例化:通过在 class 后使用 <> 进行指定模板参数。例如:
    _nmsp1::myvector
    tmpvec;
  • 隐式实例化:通过函数调用或对象创建时,编译器自动推断模板参数。例如:
    _nmsp1::myvector tmpvec(12);
  • 类模板的推断指南

    在 C++ 17 中,推断指南(Deduction Guide)被进一步扩展,提供了更强大的模板参数推断能力。推断指南主要用于以下场景:

  • 隐式推断指南:当构造函数的参数类型可以唯一确定模板参数时,编译器会隐式地进行实例化。
  • 显式推断指南:通过在模板定义中定义 -> 操作符,可以指导编译器如何从构造函数的参数推断模板参数。
  • 例如,以下是一个带有显式推断指南的类模板定义:

    template 
    struct A {
    A(T val1, T val2) {}
    A(T val) {}
    };
    template
    A(T, T) -> A
    ;

    在这种情况下,调用 A aobj(15, 16) 时,编译器会根据构造函数的参数推断出 Tint

    聚合类与推断指南

    聚合类(Aggregate Class)是 C++ 中一个特殊的类模板,它允许用户直接访问成员变量,并且具有特殊的初始化语法。聚合类需要满足以下条件:

  • 所有成员都是 public
  • 没有定义构造函数。
  • 没有类内初始值。
  • 没有基类,也没有虚函数。
  • 推断指南的作用

    推断指南对于聚合类尤为重要,因为它允许用户通过简洁的语法直接构造对象。例如:

    template 
    struct B {
    T m_b;
    T m_b2;
    };
    template
    B(T) -> B
    ;
    template
    B(T, U) -> B
    ;

    在这种情况下,以下代码可以直接运行:

    B bobj { 15 };
    B bobj2 { 15, 20 };

    推断指南的应用

    在没有自定义推断指南的情况下,用户需要显式地指定模板参数。例如:

    _nmsp3::B
    bobj3;
    _nmsp3::B
    bobj4;

    通过定义自定义推断指南,可以简化代码,提高可读性。

    类模板的特化与偏特化

    类模板的特化(Specialization)是指对模板参数进行特定类型的定义,生成特化版本的类实例。特化可以分为两种形式:

  • 模板参数数量上的偏特化:限制模板参数的数量。
  • 模板参数范围上的偏特化:限制模板参数的类型。
  • 例如,以下是一个模板参数范围上的偏特化:

    template 
    struct TC {
    T m_t;
    U m_u;
    };
    template
    struct TC;

    在这种情况下,TC 只能接受指针类型的 U

    全特化与偏特化的区别

    全特化是对模板参数的全部定义生成特化版本,而偏特化只是对部分模板参数进行定义。全特化和偏特化可以结合使用,但需要注意顺序。例如:

    template 
    struct TC {
    TC() {}
    void functest();
    };
    template
    TC
    {
    TC() {}
    void functest();
    };

    在这种情况下,TC<int, int*> 是一个全特化版本,TC<int, int> 是一个偏特化版本。

    缺省参数与非类型模板参数

    模板参数可以定义缺省值,减少用户的输入。缺省参数的定义遵循以下规则:

  • 如果某个模板参数有缺省值,那么后续的模板参数也必须有缺省值。
  • 缺省参数只能出现在模板参数列表的末尾。
  • 例如,以下是一个带有缺省参数的类模板定义:

    template 
    struct TC {
    TC() {}
    void functest();
    };

    在这种情况下,TC()TU 都会被默认定义为 int

    非类型模板参数

    非类型模板参数通常用于接受编译时常量或静态数据。这些参数的类型通常是整数或指针。例如:

    template 
    struct TC {
    T m_arr[arrsize];
    void functest();
    };

    在这种情况下,arrsize 是一个非类型模板参数,T 是类型模板参数。

    非类型模板参数的限制

    非类型模板参数不能是浮点类型,因为它们需要在编译时确定大小。同时,全局指针和字符串常量不能作为非类型模板参数。

    结论

    类模板是 C++ 编程中的一个强大工具,它通过模板参数的泛化和特化,简化了代码的复杂性。通过合理使用推断指南、特化和缺省参数,可以进一步提高代码的可维护性和扩展性。了解和掌握类模板的使用,是一个每个 C++ 开发者必须掌握的核心技能。

    上一篇:【网络通信 -- 直播】开源流媒体服务器对比与 SRS 直播效果测试
    下一篇:【C/C++基础进阶系列】C/C++ 泛型 -- 函数模板

    发表评论

    最新留言

    很好
    [***.229.124.182]2025年04月22日 05时49分33秒