当前位置: 首页 > article >正文

C++ 语言特性30 - 模板介绍

目录

一:C++11 之前的模板特性

1. 函数模板:

2. 类模板:

3. 模板特化:

4. 模板参数:

5. 模板元编程:

二:C++11的模板特性 

1. 变长模板(Variadic Templates):

2. 右值引用和完美转发:

3. 类型别名模板(Type Alias Templates):

4.  decltype 关键字

5. 默认模板参数

6. 非类型模板参数

7. 模板特化

三:C++17的模板特性

1. 模板参数推导(Template Parameter Deduction for Class Templates)

2. std::optional

3. std::variant

4. if 和 switch 语句中的初始化(If and Switch with Initialization)

5. constexpr 增强

6. std::any

7.模板的 std::decay

四:C++20的模板特性

1. 概念(Concepts)

2. 模板参数的约束(Template Parameter Constraints)

3. 模板模板参数(Template Template Parameters):

 


一:C++11 之前的模板特性

  1. 函数模板

   允许定义可以接受不同类型参数的函数。函数模板在调用时根据参数类型进行实例化。

template<typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    int result1 = add(3, 4);         // 实例化为 int
    double result2 = add(3.5, 2.5);  // 实例化为 double
}

 2. 类模板

  允许定义可以接受不同类型参数的类。类模板在创建对象时根据类型参数进行实例化。

template<typename T>
class Box {
public:
    Box(T value) : value(value) {}
    T getValue() { return value; }
private:
    T value;
};

int main() {
    Box<int> intBox(10);      // 实例化为 Box<int>
    Box<std::string> strBox("Hello"); // 实例化为 Box<std::string>
}

3. 模板特化

 允许为特定类型提供不同的实现,称为模板特化。可以是完全特化或偏特化。

template<typename T>
class Box {
public:
    void print() { std::cout << "Generic Box" << std::endl; }
};

// 完全特化
template<>
class Box<int> {
public:
    void print() { std::cout << "Integer Box" << std::endl; }
};

int main() {
    Box<double> box1;
    box1.print(); // 输出 "Generic Box"

    Box<int> box2;
    box2.print(); // 输出 "Integer Box"
}

4. 模板参数

模板可以使用非类型参数,例如整数常量。

template<int size>
class Array {
public:
    int data[size]; // 使用非类型模板参数
};

int main() {
    Array<10> arr; // 创建一个大小为 10 的数组
}

 5. 模板元编程

  在 C++11 之前,模板还可以用于编写编译时计算的元编程,例如计算阶乘、斐波那契数列等。

template<int N>
struct Factorial {
    static const int value = N * Factorial<N - 1>::value;
};

template<>
struct Factorial<0> {
    static const int value = 1;
};

int main() {
    int result = Factorial<5>::value; // result 为 120
}

二:C++11的模板特性 

1. 变长模板(Variadic Templates)

允许定义接受可变数量参数的模板,简化了如容器、函数等的模板定义。

#include <iostream>

// 基础模板
template<typename T>
void print(T value) {
    std::cout << value << std::endl;
}

// 变长模板
template<typename T, typename... Args>
void print(T first, Args... args) {
    std::cout << first << ", ";
    print(args...); // 递归调用
}

int main() {
    print(1, 2.5, "Hello", 'A'); // 输出: 1, 2.5, Hello, A
}

 2. 右值引用和完美转发

引入了右值引用和 std::forward,使得模板能够更高效地处理不同类型的参数。

#include <iostream>
#include <utility>

template<typename T>
void process(T&& arg) {
    // 处理 arg
    std::cout << arg << std::endl;
}

template<typename T>
void wrapper(T&& arg) {
    process(std::forward<T>(arg)); // 完美转发
}

int main() {
    int x = 10;
    wrapper(x); // 左值
    wrapper(20); // 右值
}

3. 类型别名模板(Type Alias Templates)

使用 using 定义类型别名模板,使得模板的可读性更强。

#include <iostream>
#include <vector>

// 定义类型别名模板
template<typename T>
using Vec = std::vector<T>;

int main() {
    Vec<int> intVec; // 实际上是 std::vector<int>
    intVec.push_back(1);
    std::cout << intVec[0] << std::endl; // 输出: 1
}

4.  decltype 关键字

decltype 关键字可以用于模板中,以便在编译时推导表达式的类型。

#include <iostream>

template<typename T>
void displayType(T arg) {
    // 使用 decltype 获取类型
    decltype(arg) var = arg;
    std::cout << "Type of var: " << typeid(var).name() << std::endl;
}

int main() {
    displayType(10);          // 输出: Type of var: int
    displayType(3.14);       // 输出: Type of var: double
}

5. 默认模板参数

C++11 允许为模板参数指定默认值,这样在某些情况下可以简化调用。

#include <iostream>

template<typename T, int size = 10>
class Array {
public:
    T data[size]; // 使用默认模板参数
    void printSize() {
        std::cout << "Array size: " << size << std::endl;
    }
};

int main() {
    Array<int> arr; // 使用默认参数
    arr.printSize(); // 输出: Array size: 10

    Array<double, 20> arr2; // 指定大小
    arr2.printSize(); // 输出: Array size: 20
}

6. 非类型模板参数

C++11 引入了更多类型的非类型模板参数,例如可以使用指针和引用作为模板参数。

#include <iostream>

template<int N>
class Array {
public:
    int data[N]; // 使用非类型模板参数
    void printSize() {
        std::cout << "Array size: " << N << std::endl;
    }
};

int main() {
    Array<5> arr; // 创建大小为 5 的数组
    arr.printSize(); // 输出: Array size: 5
}

7. 模板特化

在 C++11 中,你可以使用完全特化和部分特化来处理特定类型的情况。

#include <iostream>

// 基础模板
template<typename T>
class Box {
public:
    void display() { std::cout << "Generic Box" << std::endl; }
};

// 完全特化
template<>
class Box<int> {
public:
    void display() { std::cout << "Integer Box" << std::endl; }
};

int main() {
    Box<double> box1;
    box1.display(); // 输出: Generic Box

    Box<int> box2;
    box2.display(); // 输出: Integer Box
}

三:C++17的模板特性

1. 模板参数推导(Template Parameter Deduction for Class Templates)

C++17 允许在类模板中通过构造函数自动推导类型参数,从而简化模板的使用。

#include <iostream>

template<typename T>
class Wrapper {
public:
    Wrapper(T value) : value(value) {}
    T getValue() const { return value; }
private:
    T value;
};

int main() {
    Wrapper w(42); // T 被推导为 int
    std::cout << w.getValue() << std::endl; // 输出: 42

    Wrapper<double> w2(3.14); // 显式指定类型
    std::cout << w2.getValue() << std::endl; // 输出: 3.14
}

2. std::optional

C++17 引入了 std::optional,用于表示可能没有值的情况,结合模板使用时非常方便。

#include <iostream>
#include <optional>

std::optional<int> findValue(bool exists) {
    if (exists) return 42;
    return std::nullopt; // 表示无值
}

int main() {
    auto value = findValue(true);
    if (value) {
        std::cout << *value << std::endl; // 输出: 42
    } else {
        std::cout << "No value found" << std::endl;
    }
    
    auto noValue = findValue(false);
    if (!noValue) {
        std::cout << "No value found" << std::endl; // 输出: No value found
    }
}

3. std::variant

std::variant 是 C++17 引入的一个类型安全的联合体,允许多个类型的值共存。

#include <iostream>
#include <variant>

std::variant<int, double, std::string> getValue(bool flag) {
    if (flag) return 10;
    return 3.14; // 返回 double
}

int main() {
    auto value = getValue(true);
    
    // 使用 std::visit 处理 variant
    std::visit([](auto&& arg) {
        std::cout << arg << std::endl; // 输出: 10
    }, value);

    value = getValue(false);
    std::visit([](auto&& arg) {
        std::cout << arg << std::endl; // 输出: 3.14
    }, value);
}

4. ifswitch 语句中的初始化(If and Switch with Initialization)

C++17 允许在 ifswitch 语句中直接进行初始化,增强了代码的简洁性。

#include <iostream>

bool checkValue() {
    return true;
}

int main() {
    // 在 if 语句中初始化
    if (auto value = checkValue()) {
        std::cout << "Value is true" << std::endl;
    } else {
        std::cout << "Value is false" << std::endl;
    }
}

5. constexpr 增强

C++17 扩展了 constexpr 的功能,使得模板可以在编译时进行更多计算。

#include <iostream>

constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

int main() {
    constexpr int value = factorial(5); // 在编译时计算
    std::cout << "Factorial of 5: " << value << std::endl; // 输出: Factorial of 5: 120
}

6. std::any

std::any 是 C++17 引入的另一种类型安全的容器,允许存储任意类型的值。

#include <iostream>
#include <any>

int main() {
    std::any anyValue = 10; // 存储整数
    std::cout << std::any_cast<int>(anyValue) << std::endl; // 输出: 10

    anyValue = std::string("Hello, World!"); // 存储字符串
    std::cout << std::any_cast<std::string>(anyValue) << std::endl; // 输出: Hello, World!
}

7.模板的 std::decay

C++17 引入了 std::decay,用于获取参数类型的“衰变”类型,常用于模板中。

#include <iostream>
#include <type_traits>

template<typename T>
void printType(T&& arg) {
    using DecayedType = typename std::decay<T>::type;
    std::cout << "Type: " << typeid(DecayedType).name() << std::endl;
}

int main() {
    int x = 10;
    printType(x); // 输出类型为 int
    printType(20); // 输出类型为 int
    printType("Hello"); // 输出类型为 const char*
}

四:C++20的模板特性

1. 概念(Concepts)

概念用于定义模板参数的约束条件,使得模板编程更加类型安全和可读。

#include <iostream>
#include <concepts>

// 定义一个概念:必须是可加的类型
template<typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::same_as<T>;
};

template<Addable T>
T add(T a, T b) {
    return a + b;
}

int main() {
    std::cout << add(5, 10) << std::endl; // 输出: 15
    // std::cout << add(5.5, 2.5) << std::endl; // 正确,输出: 8.0
    // std::cout << add("Hello", "World"); // 错误,类型不满足 Addable 概念
}

2. 模板参数的约束(Template Parameter Constraints)

C++20 允许在模板定义中直接使用概念作为参数约束,增加了代码的可读性和类型安全。

#include <iostream>
#include <concepts>

template<typename T>
void process(T value) requires std::integral<T> {
    std::cout << "Processing integral value: " << value << std::endl;
}

int main() {
    process(10); // 正确
    // process(3.14); // 错误,double 不是整数
}

3. 模板模板参数(Template Template Parameters)

增强了对模板模板参数的支持,可以更灵活地处理各种模板结构。

template<template<typename> class Container, typename T>
void process(Container<T> c) {
    // 处理容器
}


http://www.kler.cn/news/340365.html

相关文章:

  • 安卓APP 构建
  • Meta MovieGen AI:颠覆性的文本生成视频技术详解
  • 机器学习中的回归分析:理论与实践
  • 基于SSM的校园教务系统的设计与实现(论文+源码)_kaic
  • Python数据分析-城市空气质量与健康影响分析
  • node高版本报错: digital envelope routines::unsupported
  • MySQL,多条件分页查询语句
  • swift使用代码结构解析
  • CNN+Transformer解说
  • 探讨最好用的AI工具:从日常到创新的应用
  • Linux内核 -- 使用 `proc_create_seq` 和 `seq_operations` 快速创建 /proc 文件
  • [C++ 核心编程]笔记 3 引用做函数参数
  • Web前端入门
  • 手机 电脑 Pad 是如何得到IP地址的呢? 如何让你的设备自动获取IP地址?DHCP :给你 IP 地址的隐形人
  • Qt-窗口布局按钮输入类
  • 基于Springboot+Vue的服装生产管理信息系统设计与实现(含源码数据库)
  • Java 实现 Feed 流实时更新数据的设计与实现
  • FLORR.IO画廊(3)
  • 产品需求文档PRD
  • 【黑马软件测试三】web功能测试、抓包