C++ 模板【笔记】

1. 模板基础与编译原理

模板的编译过程

cpp 复制代码
// 模板定义(通常在头文件中)
template<typename T>
class Vector {
private:
    T* data_;
    size_t size_;
    
public:
    Vector(size_t size) : size_(size), data_(new T[size]) {}
    ~Vector() { delete[] data_; }
    
    T& operatorsize_t index { return data_[index]; }
    const T& operatorsize_t index const { return data_[index]; }
};

// 模板实例化(编译器在编译时生成具体代码)
Vector<int> int_vec(10);    // 实例化 Vector<int>
Vector<double> double_vec(5); // 实例化 Vector<double>

两阶段编译机制

cpp 复制代码
template<typename T>
void process(T value) {
    value.non_existent_method();  // 第一阶段:语法检查通过
                                  // 第二阶段:实例化时才会报错
}

int main() {
    process(42);  // 编译错误:int没有non_existent_method方法
}

2. 函数模板深度解析

模板参数推导机制

cpp 复制代码
template<typename T>
T max(T a, T b) {
    return a > b ? a : b;
}

// 推导示例
max(1, 2);        // T = int
max(1.0, 2.0);    // T = double
max<int>(1, 2.5); // 显式指定T=int,2.5被转换为int

// 复杂的类型推导
template<typename T>
void f(T param) {}

int x = 42;
const int cx = x;
const int& rx = x;

f(x);   // T = int, param = int
f(cx);  // T = int, param = int(const被忽略)
f(rx);  // T = int, param = int(引用和const被忽略)

完美转发与引用折叠

cpp 复制代码
template<typename T>
void forward_value(T&& arg) {  // 万能引用
    process_value(std::forward<T>(arg));  // 完美转发
}

// 引用折叠规则:
// T& &   -> T&
// T& &&  -> T&  
// T&& &  -> T&
// T&& && -> T&&

int x = 42;
forward_value(x);           // T = int&, arg = int&
forward_value(std::move(x));// T = int, arg = int&&
forward_value(100);         // T = int, arg = int&&

SFINAE(替换失败不是错误)

cpp 复制代码
// 检测类型是否有serialize方法
template<typename T>
class has_serialize {
private:
    template<typename U>
    static auto test(int) -> decltype(std::declval<U>().serialize(), std::true_type{});
    
    template<typename U>
    static std::false_type test(...);
    
public:
    static constexpr bool value = decltype(test<T>(0))::value;
};

// 应用:根据特性选择实现
template<typename T>
std::enable_if_t<has_serialize<T>::value, std::string>
serialize(const T& obj) {
    return obj.serialize();  // 使用成员方法
}

template<typename T>
std::enable_if_t<!has_serialize<T>::value, std::string>
serialize(const T& obj) {
    return std::to_string(obj);  // 使用通用转换
}

3. 类模板高级特性

模板特化与偏特化

cpp 复制代码
// 主模板
template<typename T>
class TypeInfo {
public:
    static const char* name() { return "unknown"; }
};

// 全特化
template<>
class TypeInfo<int> {
public:
    static const char* name() { return "int"; }
};

// 偏特化(指针类型)
template<typename T>
class TypeInfo<T*> {
public:
    static const char* name() { return "pointer"; }
};

// 偏特化(引用类型)
template<typename T>
class TypeInfo<T&> {
public:
    static const char* name() { return "reference"; }
};

可变参数模板

cpp 复制代码
// 递归展开
template<typename T>
void print(T value) {
    std::cout << value << std::endl;
}

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

// 折叠表达式(C++17)
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);  // 折叠表达式
}

// 完美转发的可变参数
template<typename... Args>
void emplace_back(Args&&... args) {
    // 使用完美转发构造对象
    new (storage) T(std::forward<Args>(args)...);
}

模板元编程

cpp 复制代码
// 编译时计算斐波那契数列
template<int N>
struct Fibonacci {
    static constexpr int value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
};

template<>
struct Fibonacci<0> {
    static constexpr int value = 0;
};

template<>
struct Fibonacci<1> {
    static constexpr int value = 1;
};

// 使用
constexpr int fib10 = Fibonacci<10>::value;  // 编译时计算

// 类型列表操作
template<typename... Types>
class TypeList {};

template<typename List>
class Front;

template<typename Head, typename... Tail>
class Front<TypeList<Head, Tail...>> {
public:
    using type = Head;
};

using MyList = TypeList<int, double, std::string>;
using FirstType = Front<MyList>::type;  // int

4. 模板设计模式与技巧

CRTP(奇异递归模板模式)

cpp 复制代码
// 静态多态
template<typename Derived>
class Base {
public:
    void interface() {
        static_cast<Derived*>(this)->implementation();
    }
    
    static void static_interface() {
        Derived::static_implementation();
    }
};

class Derived1 : public Base<Derived1> {
public:
    void implementation() {
        std::cout << "Derived1 implementation\n";
    }
    
    static void static_implementation() {
        std::cout << "Derived1 static implementation\n";
    }
};

// 应用:对象计数
template<typename T>
class ObjectCounter {
private:
    inline static int count_ = 0;
    
protected:
    ObjectCounter() { ++count_; }
    ObjectCounter(const ObjectCounter&) { ++count_; }
    ObjectCounter(ObjectCounter&&) { ++count_; }
    ~ObjectCounter() { --count_; }
    
public:
    static int alive() { return count_; }
};

class MyClass : public ObjectCounter<MyClass> {
    // 自动获得对象计数功能
};

策略模式与模板

cpp 复制代码
// 排序策略
template<typename T>
struct QuickSort {
    void sort(std::vector<T>& data) {
        std::sort(data.begin(), data.end());
    }
};

template<typename T>
struct MergeSort {
    void sort(std::vector<T>& data) {
        // 实现归并排序
    }
};

// 使用策略的容器
template<typename T, typename SortStrategy = QuickSort<T>>
class SortedContainer {
private:
    std::vector<T> data_;
    SortStrategy sorter_;
    
public:
    void add(const T& value) {
        data_.push_back(value);
        sorter_.sort(data_);
    }
};

// 使用
SortedContainer<int, QuickSort<int>> quick_container;
SortedContainer<int, MergeSort<int>> merge_container;

类型萃取(Type Traits)

cpp 复制代码
// 自定义类型萃取
template<typename T>
struct is_pointer : std::false_type {};

template<typename T>
struct is_pointer<T*> : std::true_type {};

template<typename T>
struct is_numeric {
    static constexpr bool value = 
        std::is_integral_v<T> || std::is_floating_point_v<T>;
};

// 应用:根据类型选择算法
template<typename T>
void process(T value) {
    if constexpr (is_numeric<T>::value) {
        // 数值类型的优化处理
        std::cout << "Numeric: " << value * 2 << std::endl;
    } else if constexpr (std::is_pointer_v<T>) {
        // 指针类型的特殊处理
        std::cout << "Pointer: " << *value << std::endl;
    } else {
        // 通用处理
        std::cout << "Generic: " << value << std::endl;
    }
}

5. 模板性能优化

编译期优化技术

cpp 复制代码
// 编译期字符串处理
template<size_t N>
struct FixedString {
    char data[N] = {};
    
    constexpr FixedString(const char (&str)[N]) {
        std::copy_n(str, N, data);
    }
    
    constexpr bool operator==(const FixedString& other) const {
        return std::equal(data, data + N, other.data);
    }
};

// 编译期哈希
template<FixedString Str>
constexpr size_t hash() {
    size_t result = 0;
    for (size_t i = 0; i < sizeof(Str.data); ++i) {
        result = (result * 131) + Str.data[i];
    }
    return result;
}

// 使用
constexpr auto str = FixedString("hello");
constexpr size_t h = hash<str>();  // 编译期计算

内联与优化

cpp 复制代码
// 小函数模板通常会被内联
template<typename T>
T square(T x) {  // 很可能被内联
    return x * x;
}

// 避免模板代码膨胀
template<typename T>
class Pimpl {
private:
    struct Implementation;  // 前向声明
    std::unique_ptr<Implementation> pimpl_;  // 隐藏实现细节
    
public:
    // 接口函数,不依赖具体类型
    void do_something();
};

// 显式实例化减少编译时间
// 在头文件中声明
template<typename T>
class ExpensiveTemplate {
    // 复杂的模板实现
};

// 在源文件中显式实例化
template class ExpensiveTemplate<int>;
template class ExpensiveTemplate<double>;

6. 现代C++模板特性

C++17 特性

cpp 复制代码
// 类模板参数推导
std::pair p(1, 2.0);        // 推导为 std::pair<int, double>
std::vector v{1, 2, 3};     // 推导为 std::vector<int>

// if constexpr
template<typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}

// 折叠表达式
template<typename... Args>
bool all_true(Args... args) {
    return (args && ...);  // 逻辑与折叠
}

C++20 概念(Concepts)

cpp 复制代码
// 定义概念
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;

template<typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::same_as<T>;
};

// 使用概念约束模板
template<Numeric T>
T square(T x) {
    return x * x;
}

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

// 简写语法
auto add(Addable auto a, Addable auto b) {
    return a + b;
}

7. 模板调试与错误处理

静态断言

cpp 复制代码
template<typename T>
class Vector {
    static_assert(std::is_default_constructible_v<T>, 
                  "T must be default constructible");
    
public:
    // 实现...
};

// 自定义错误消息
template<typename From, typename To>
void convert(const From& from, To& to) {
    static_assert(std::is_convertible_v<From, To>,
        "Cannot convert between these types");
    to = static_cast<To>(from);
}

编译时调试

cpp 复制代码
// 类型打印工具
template<typename T>
void print_type() {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

// 使用
print_type<std::vector<int>>();
// 输出:void print_type() [T = std::vector<int>]

// 概念检查工具
template<typename T>
concept Checkable = requires {
    requires sizeof(T) > 4;
    requires std::is_copy_constructible_v<T>;
};

static_assert(Checkable<int>);  // 编译时检查

8. 最佳实践总结

模板设计原则

cpp 复制代码
// 1. 优先使用函数对象而非函数指针
template<typename Func>
void execute(Func func) {  // 更好的内联机会
    func();
}

// 2. 提供完整的类型约束
template<typename T> requires std::copyable<T>
class Container {
    // 明确要求T可拷贝
};

// 3. 使用SFINAE友好技术
template<typename T>
auto begin(T& container) -> decltype(container.begin()) {
    return container.begin();
}

template<typename T, size_t N>
T* begin(T (&array)[N]) {
    return array;
}

// 4. 避免过度泛化
template<typename T>
class Matrix {  // 合理的泛化
    // 矩阵运算
};

template<typename T>
class UniversalContainer {  // 过度泛化,难以维护
    // 试图满足所有需求的容器
};

性能优化指南

cpp 复制代码
// 1. 小函数模板放在头文件中
template<typename T>
inline T min(T a, T b) {  // inline提示编译器优化
    return a < b ? a : b;
}

// 2. 使用移动语义优化模板
template<typename T>
class Wrapper {
private:
    T value_;
    
public:
    // 完美转发构造函数
    template<typename U>
    Wrapper(U&& value) : value_(std::forward<U>(value)) {}
    
    // 移动操作
    Wrapper(Wrapper&&) = default;
    Wrapper& operator=(Wrapper&&) = default;
};

// 3. 避免不必要的模板实例化
template<typename T>
void process_impl(T value) {  // 内部实现
    // 复杂逻辑
}

template<typename T>
void process(T value) {  // 对外接口
    if (value.is_valid()) {  // 提前检查,避免不必要的实例化
        process_impl(value);
    }
}
相关推荐
菩提祖师_43 分钟前
基于VR的虚拟会议系统设计
开发语言·javascript·c++·爬虫
古城小栈1 小时前
Rust 闭包 敲黑板
开发语言·rust
GrowingYi1 小时前
Go语言的特性
开发语言·后端·golang
YxVoyager1 小时前
Qt C++ :QJson使用详解
c++·qt
小尧嵌入式1 小时前
c++红黑树及B树B+树
开发语言·数据结构·c++·windows·b树·算法·排序算法
cike_y1 小时前
Spring整合Mybatis:dao层
java·开发语言·数据库·spring·mybatis
松涛和鸣1 小时前
45、无依赖信息查询系统(C语言+SQLite3+HTML)
c语言·开发语言·数据库·单片机·sqlite·html
feifeigo1231 小时前
基于C#实现即时通讯工具
开发语言·c#
这是程序猿1 小时前
基于java的SpringBoot框架医院药品管理系统
java·开发语言·spring boot·后端·spring·医院药品管理系统
yousuotu1 小时前
基于Python实现水果新鲜度分类
开发语言·python·分类