19.2 模板元编程基础

相关章节

在本节中你将学到…

  • 模板特化与偏特化的区别和应用场景
  • 递归模板实例化的工作原理
  • 编译期计算的技术和技巧
  • type_traits的使用和自定义
  • 模板元编程在CGAL中的实际应用

19.2.0 类比解释:建筑预制构件

生活场景类比

想象你要建造一排相似的房子。传统方式是现场一块砖一块砖地砌(运行时计算)。而现代建筑使用预制构件(编译期计算):在工厂里预先制作好墙板、楼梯等部件,现场只需组装。

模板元编程就像建筑预制

  • 设计阶段(编译期):根据模板生成具体的代码
  • 建造阶段(运行时):执行已经生成好的代码
  • 优势:更快、更高效、错误在设计阶段就被发现

具体类比

运行时计算(传统编程):
  建筑师画草图 → 工人现场砌墙 → 发现问题返工
  
编译期计算(模板元编程):
  建筑师详细设计 → 工厂预制构件 → 现场快速组装
  
  优势:
  1. 设计错误在工厂就被发现,不会带到工地
  2. 构件可以精确优化,现场无需再计算
  3. 组装速度快,因为复杂工作已完成

为什么需要模板元编程?

场景1:类型相关的代码重复

// 没有TMP时,需要为每种类型写重载
int max(int a, int b) { return a > b ? a : b; }
double max(double a, double b) { return a > b ? a : b; }
float max(float a, float b) { return a > b ? a : b; }
// ... 重复无数次

场景2:编译期条件判断

// 根据类型特性选择不同实现
// 对于整数,使用快速算法
// 对于浮点数,需要考虑精度
// 对于自定义类型,使用通用算法

场景3:编译期数值计算

// 运行时计算阶乘(有开销)
int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}
 
// 编译期计算阶乘(零开销)
template <int N>
struct Factorial {
    static const int value = N * Factorial<N - 1>::value;
};
 
template <>
struct Factorial<0> {
    static const int value = 1;
};
 
// 使用:Factorial<5>::value 在编译期等于 120

19.2.1 概念解释

什么是模板元编程?

模板元编程(Template Metaprogramming,TMP)是利用C++模板机制在编译期执行计算和代码生成的技术。它让编译器成为一个”程序生成器”,在编译时完成原本需要在运行时完成的工作。

类比理解:想象你是一位建筑设计师。普通编程就像在现场一块砖一块砖地砌墙;而模板元编程就像是在设计阶段就预制好所有构件,现场只需要组装即可。结果是更快、更高效的建造过程。

编译期 vs 运行期

运行时计算:
  源代码 → 编译 → 可执行文件 → 运行 → 计算结果

编译期计算(TMP):
  源代码 → 编译(执行TMP)→ 优化后的可执行文件 → 运行
                                      ↑
                                 计算已完成

关键优势

  1. 零运行时开销:计算在编译期完成
  2. 类型安全:错误在编译期捕获
  3. 代码优化:编译器可以生成高度优化的代码

可视化

程序构建流程对比:

传统编程:
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│ 源代码   │ → │ 编译器   │ → │ 可执行文件│ → │ 运行时计算│
│         │    │         │    │         │    │ (慢)     │
└─────────┘    └─────────┘    └─────────┘    └─────────┘

模板元编程:
┌─────────┐    ┌─────────────────────┐    ┌─────────┐
│ 源代码   │ → │ 编译器(执行TMP)    │ → │ 可执行文件│
│ + 模板   │    │ - 类型计算           │    │ (已优化) │
│         │    │ - 代码生成           │    │         │
│         │    │ - 编译期决策         │    │         │
└─────────┘    └─────────────────────┘    └─────────┘
                                                    ↓
                                              ┌─────────┐
                                              │ 直接执行 │
                                              │ (快)    │
                                              └─────────┘

19.2.2 为什么需要模板元编程?

问题1:类型相关的代码重复

// 没有TMP时,需要为每种类型写重载
int max(int a, int b) { return a > b ? a : b; }
double max(double a, double b) { return a > b ? a : b; }
float max(float a, float b) { return a > b ? a : b; }
// ... 重复无数次

解决方案:一个模板搞定所有类型

template <typename T>
T max(T a, T b) { return a > b ? a : b; }

问题2:编译期条件判断

需要根据类型特性选择不同实现:

// 对于整数,使用快速算法
// 对于浮点数,需要考虑精度
// 对于自定义类型,使用通用算法

解决方案:条件模板特化

template <typename T, bool is_integral>
struct optimized_algorithm;
 
// 整数特化
template <typename T>
struct optimized_algorithm<T, true> { /* 快速实现 */ };
 
// 非整数特化
template <typename T>
struct optimized_algorithm<T, false> { /* 通用实现 */ };

问题3:编译期数值计算

// 运行时计算阶乘(有开销)
int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}
 
// 编译期计算阶乘(零开销)
template <int N>
struct Factorial {
    static const int value = N * Factorial<N - 1>::value;
};
 
template <>
struct Factorial<0> {
    static const int value = 1;
};
 
// 使用:Factorial<5>::value 在编译期等于 120

19.2.3 代码示例

基础示例:模板特化

#include <iostream>
#include <type_traits>
 
// ============================================
// 基础:主模板(Primary Template)
// ============================================
 
template <typename T>
struct TypeInfo {
    static constexpr bool is_special = false;
    static const char* name() { return "unknown"; }
    static constexpr int size = sizeof(T);
};
 
// ============================================
// 全特化(Full Specialization)
// ============================================
 
// 为int提供特化
template <>
struct TypeInfo<int> {
    static constexpr bool is_special = true;
    static const char* name() { return "int"; }
    static constexpr int size = sizeof(int);
    static constexpr bool is_integer = true;
};
 
// 为double提供特化
template <>
struct TypeInfo<double> {
    static constexpr bool is_special = true;
    static const char* name() { return "double"; }
    static constexpr int size = sizeof(double);
    static constexpr bool is_floating = true;
};
 
// 为void*提供特化
template <>
struct TypeInfo<void*> {
    static constexpr bool is_special = true;
    static const char* name() { return "void*"; }
    static constexpr int size = sizeof(void*);
    static constexpr bool is_pointer = true;
};
 
int main() {
    std::cout << "TypeInfo<float>::name() = " 
              << TypeInfo<float>::name() << std::endl;  // unknown
    
    std::cout << "TypeInfo<int>::name() = " 
              << TypeInfo<int>::name() << std::endl;    // int
    
    std::cout << "TypeInfo<double>::size = " 
              << TypeInfo<double>::size << std::endl;  // 8
    
    return 0;
}

可视化

模板实例化过程:

TypeInfo<int>
    ↓
查找特化:找到全特化 TypeInfo<int>
    ↓
使用特化版本:
    - is_special = true
    - name() = "int"
    - is_integer = true

TypeInfo<float>
    ↓
查找特化:无特化
    ↓
使用主模板:
    - is_special = false
    - name() = "unknown"

中级示例:偏特化

#include <iostream>
#include <cstddef>
 
// ============================================
// 偏特化(Partial Specialization)
// ============================================
 
// 主模板:处理一般情况
template <typename T>
struct ContainerTraits {
    static constexpr bool is_container = false;
    static constexpr bool is_pointer = false;
    static constexpr bool is_reference = false;
};
 
// 偏特化1:所有指针类型
template <typename T>
struct ContainerTraits<T*> {
    static constexpr bool is_container = false;
    static constexpr bool is_pointer = true;
    static constexpr bool is_reference = false;
    typedef T value_type;  // 去掉指针后的类型
};
 
// 偏特化2:所有引用类型
template <typename T>
struct ContainerTraits<T&> {
    static constexpr bool is_container = false;
    static constexpr bool is_pointer = false;
    static constexpr bool is_reference = true;
    typedef T value_type;  // 去掉引用后的类型
};
 
// 偏特化3:const指针
template <typename T>
struct ContainerTraits<const T*> {
    static constexpr bool is_container = false;
    static constexpr bool is_pointer = true;
    static constexpr bool is_reference = false;
    static constexpr bool is_const = true;
    typedef T value_type;
};
 
// 偏特化4:数组类型
template <typename T, size_t N>
struct ContainerTraits<T[N]> {
    static constexpr bool is_container = true;
    static constexpr bool is_array = true;
    static constexpr size_t size = N;
    typedef T value_type;
};
 
// 偏特化5:const数组
template <typename T, size_t N>
struct ContainerTraits<const T[N]> {
    static constexpr bool is_container = true;
    static constexpr bool is_array = true;
    static constexpr bool is_const = true;
    static constexpr size_t size = N;
    typedef T value_type;
};
 
int main() {
    int x = 5;
    int* p = &x;
    int arr[10];
    const int carr[20];
    
    std::cout << std::boolalpha;
    
    // 测试指针
    std::cout << "int*: is_pointer = " 
              << ContainerTraits<int*>::is_pointer << std::endl;
    
    // 测试引用
    std::cout << "int&: is_reference = " 
              << ContainerTraits<int&>::is_reference << std::endl;
    
    // 测试数组
    std::cout << "int[10]: size = " 
              << ContainerTraits<int[10]>::size << std::endl;
    
    // 测试const数组
    std::cout << "const int[20]: is_const = " 
              << ContainerTraits<const int[20]>::is_const << std::endl;
    
    return 0;
}

可视化

偏特化匹配过程:

ContainerTraits<int*>
    ↓
匹配:主模板?否
匹配:T* 偏特化?是(T=int)
    ↓
使用偏特化:
    - is_pointer = true
    - value_type = int

ContainerTraits<int[10]>
    ↓
匹配:主模板?否
匹配:T[N] 偏特化?是(T=int, N=10)
    ↓
使用偏特化:
    - is_container = true
    - size = 10
    - value_type = int

高级示例:递归模板实例化

#include <iostream>
 
// ============================================
// 编译期数值计算:阶乘
// ============================================
 
// 主模板:递归定义
template <int N>
struct Factorial {
    // 递归:N\! = N * (N-1)\!
    static constexpr int value = N * Factorial<N - 1>::value;
};
 
// 特化:递归终止条件
template <>
struct Factorial<0> {
    static constexpr int value = 1;
};
 
// ============================================
// 编译期数值计算:斐波那契数列
// ============================================
 
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;
};
 
// ============================================
// 编译期类型选择
// ============================================
 
// 条件类型选择(类似C++11的std::conditional)
template <bool Condition, typename TrueType, typename FalseType>
struct If {
    typedef TrueType type;
};
 
template <typename TrueType, typename FalseType>
struct If<false, TrueType, FalseType> {
    typedef FalseType type;
};
 
// ============================================
// 编译期循环:类型列表
// ============================================
 
// 类型列表的节点
template <typename Head, typename Tail>
struct TypeList {
    typedef Head head;
    typedef Tail tail;
};
 
// 空列表标记
struct NullType {};
 
// 获取列表长度
template <typename List>
struct Length {
    static constexpr int value = 1 + Length<typename List::tail>::value;
};
 
template <>
struct Length<NullType> {
    static constexpr int value = 0;
};
 
// 获取第N个类型
template <typename List, int N>
struct Get {
    typedef typename Get<typename List::tail, N - 1>::type type;
};
 
template <typename List>
struct Get<List, 0> {
    typedef typename List::head type;
};
 
// ============================================
// 编译期类型转换
// ============================================
 
// 移除const修饰符
template <typename T>
struct RemoveConst {
    typedef T type;
};
 
template <typename T>
struct RemoveConst<const T> {
    typedef T type;
};
 
// 移除引用
template <typename T>
struct RemoveReference {
    typedef T type;
};
 
template <typename T>
struct RemoveReference<T&> {
    typedef T type;
};
 
template <typename T>
struct RemoveReference<T&&> {
    typedef T type;
};
 
// 组合:移除const和引用
template <typename T>
struct Decay {
    typedef typename RemoveConst<
        typename RemoveReference<T>::type
    >::type type;
};
 
int main() {
    // 测试阶乘
    std::cout << "5\! = " << Factorial<5>::value << std::endl;  // 120
    std::cout << "10\! = " << Factorial<10>::value << std::endl;  // 3628800
    
    // 测试斐波那契
    std::cout << "Fib(10) = " << Fibonacci<10>::value << std::endl;  // 55
    
    // 测试条件选择
    typedef If<true, int, double>::type Type1;   // int
    typedef If<false, int, double>::type Type2;  // double
    
    std::cout << "sizeof(Type1) = " << sizeof(Type1) << std::endl;  // 4
    std::cout << "sizeof(Type2) = " << sizeof(Type2) << std::endl;  // 8
    
    // 测试类型列表
    typedef TypeList<int, 
            TypeList<double, 
            TypeList<char, NullType>>> MyList;
    
    std::cout << "List length = " << Length<MyList>::value << std::endl;  // 3
    
    // 获取第1个类型(double)
    typedef Get<MyList, 1>::type SecondType;
    std::cout << "sizeof(SecondType) = " << sizeof(SecondType) << std::endl;  // 8
    
    // 测试Decay
    typedef Decay<const int&>::type DecayedType;
    std::cout << "Decay<const int&> is int: " 
              << std::is_same<DecayedType, int>::value << std::endl;
    
    return 0;
}

递归实例化可视化

Factorial<5>::value 的计算过程:

Factorial<5>
    ↓ value = 5 * Factorial<4>::value
Factorial<4>
    ↓ value = 4 * Factorial<3>::value
Factorial<3>
    ↓ value = 3 * Factorial<2>::value
Factorial<2>
    ↓ value = 2 * Factorial<1>::value
Factorial<1>
    ↓ value = 1 * Factorial<0>::value
Factorial<0>
    ↓ value = 1(终止条件)

回代计算:
Factorial<1> = 1 * 1 = 1
Factorial<2> = 2 * 1 = 2
Factorial<3> = 3 * 2 = 6
Factorial<4> = 4 * 6 = 24
Factorial<5> = 5 * 24 = 120

编译期结果:Factorial<5>::value = 120

完整示例:类型特征系统

#include <iostream>
#include <type_traits>
#include <vector>
#include <list>
 
// ============================================
// 完整的类型特征系统
// ============================================
 
// 1. 判断类型是否为容器
template <typename T>
struct IsContainer {
    static constexpr bool value = false;
};
 
template <typename T, typename Alloc>
struct IsContainer<std::vector<T, Alloc>> {
    static constexpr bool value = true;
};
 
template <typename T, typename Alloc>
struct IsContainer<std::list<T, Alloc>> {
    static constexpr bool value = true;
};
 
// 2. 获取容器的值类型
template <typename T>
struct ValueType {
    typedef T type;
};
 
template <typename T, typename Alloc>
struct ValueType<std::vector<T, Alloc>> {
    typedef T type;
};
 
template <typename T, typename Alloc>
struct ValueType<std::list<T, Alloc>> {
    typedef T type;
};
 
// 3. 类型选择器
template <bool Condition, typename TrueType, typename FalseType>
struct Select {
    typedef TrueType type;
};
 
template <typename TrueType, typename FalseType>
struct Select<false, TrueType, FalseType> {
    typedef FalseType type;
};
 
// 4. 编译期最大值/最小值
template <int A, int B>
struct Max {
    static constexpr int value = (A > B) ? A : B;
};
 
template <int A, int B>
struct Min {
    static constexpr int value = (A < B) ? A : B;
};
 
// 5. 编译期类型大小比较
template <typename T1, typename T2>
struct IsLarger {
    static constexpr bool value = sizeof(T1) > sizeof(T2);
};
 
// 6. 选择较大的类型
template <typename T1, typename T2>
struct LargerType {
    typedef typename Select<IsLarger<T1, T2>::value, T1, T2>::type type;
};
 
// ============================================
// 使用类型特征的通用算法
// ============================================
 
// 根据类型特征选择最优算法
template <typename Container>
void optimized_process(Container& c) {
    process_impl(c, std::integral_constant<bool, IsContainer<Container>::value>{});
}
 
// 容器版本
template <typename Container>
void process_impl(Container& c, std::true_type) {
    std::cout << "Processing container with " << c.size() << " elements" << std::endl;
    // 容器特定优化...
}
 
// 非容器版本
template <typename T>
void process_impl(T& value, std::false_type) {
    std::cout << "Processing single value" << std::endl;
    // 单值处理...
}
 
// ============================================
// 编译期计算数组大小
// ============================================
 
template <typename T, size_t N>
constexpr size_t array_size(T (&)[N]) {
    return N;
}
 
// ============================================
// 编译期幂运算
// ============================================
 
template <int Base, int Exponent>
struct Power {
    static constexpr int value = Base * Power<Base, Exponent - 1>::value;
};
 
template <int Base>
struct Power<Base, 0> {
    static constexpr int value = 1;
};
 
// ============================================
// 编译期整数序列(C++14的integer_sequence简化版)
// ============================================
 
template <int... Ints>
struct IntSequence {};
 
template <int N, int... Ints>
struct MakeIntSequence : MakeIntSequence<N - 1, N - 1, Ints...> {};
 
template <int... Ints>
struct MakeIntSequence<0, Ints...> {
    typedef IntSequence<Ints...> type;
};
 
int main() {
    std::cout << std::boolalpha;
    
    // 测试IsContainer
    std::cout << "IsContainer<std::vector<int>>: " 
              << IsContainer<std::vector<int>>::value << std::endl;
    std::cout << "IsContainer<int>: " 
              << IsContainer<int>::value << std::endl;
    
    // 测试ValueType
    typedef ValueType<std::vector<double>>::type VT;
    std::cout << "ValueType<vector<double>> is double: " 
              << std::is_same<VT, double>::value << std::endl;
    
    // 测试Max/Min
    std::cout << "Max<3, 7>::value = " << Max<3, 7>::value << std::endl;
    std::cout << "Min<3, 7>::value = " << Min<3, 7>::value << std::endl;
    
    // 测试LargerType
    typedef LargerType<short, long>::type Larger;
    std::cout << "sizeof(LargerType<short, long>) = " << sizeof(Larger) << std::endl;
    
    // 测试Power
    std::cout << "2^10 = " << Power<2, 10>::value << std::endl;
    
    // 测试数组大小
    int arr[] = {1, 2, 3, 4, 5};
    std::cout << "Array size: " << array_size(arr) << std::endl;
    
    // 测试处理函数
    std::vector<int> vec = {1, 2, 3};
    int x = 5;
    optimized_process(vec);  // 容器版本
    optimized_process(x);    // 单值版本
    
    return 0;
}

19.2.4 CGAL中的应用

CGAL的type_traits实现

CGAL在STL_Extension/include/CGAL/type_traits.h中提供了许多类型特征:

// 来自CGAL源代码
namespace CGAL {
 
// 检查一个类型是否继承自另一个类型(或相同)
template< class Base, class Derived >
struct is_same_or_derived :
  public std::bool_constant<
    ::std::is_same_v< Base, Derived > ||
    ::boost::is_base_and_derived< Base, Derived >::value
  >
{};
 
// 检查类型是否可以无异常移动
template<typename T>
struct is_nothrow_movable :
  public std::bool_constant<
    std::is_nothrow_move_constructible_v<T> &&
    std::is_nothrow_move_assignable_v<T>
  >
{};
 
// C++20特性回退
template<class T>
struct remove_cvref {
    typedef std::remove_cv_t<std::remove_reference_t<T>> type;
};
 
} // namespace CGAL

CGAL中的First_if_different

// 来自 CGAL/Kernel/mpl.h
namespace CGAL {
 
// 如果A和B不同,返回A;否则返回空类型
// 用于避免函数重载时的歧义
template < typename A, typename B, int = 0 >
struct First_if_different {
  typedef A Type;
};
 
template < typename A, int i >
struct First_if_different<A, A, i> {
  struct Type{};  // A和B相同时返回空类型
};
 
} //namespace CGAL

使用场景:在函数重载中避免歧义

// 假设有两个重载函数
template <typename T>
void foo(T a, typename First_if_different<int, T>::Type b);
 
template <typename T>
void foo(T a, T b);  // 当T是int时,上面的重载会被禁用

CGAL中的is_iterator

// 来自 CGAL/type_traits/is_iterator.h
namespace CGAL {
namespace internal {
 
// 使用Boost.MPL检查类型是否有迭代器特征
BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator_category)
BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type)
BOOST_MPL_HAS_XXX_TRAIT_DEF(difference_type)
BOOST_MPL_HAS_XXX_TRAIT_DEF(pointer)
BOOST_MPL_HAS_XXX_TRAIT_DEF(reference)
 
// 判断是否为迭代器
template <class T>
struct is_iterator_
  : public std::bool_constant<
         ( has_iterator_category<T>::value &&
           has_value_type<T>::value &&
           has_difference_type<T>::value &&
           has_pointer<T>::value &&
           has_reference<T>::value) ||
           std::is_pointer_v<T> >
{ };
 
} // namespace internal
 
template <class T>
struct is_iterator
  : public internal::is_iterator_<std::remove_cv_t<std::remove_reference_t<T>>>
{ };
 
template <class T>
inline constexpr bool is_iterator_v = is_iterator<T>::value;
 
} // namespace CGAL

19.2.5 常见陷阱

陷阱1:递归深度过深

// 危险:编译器有模板递归深度限制(通常是几百到几千)
template <int N>
struct DeepRecursion {
    static constexpr int value = DeepRecursion<N - 1>::value;
};
 
// Factorial<1000> 可能导致编译错误!

解决方案:使用迭代而非递归,或增加编译器限制

# GCC
g++ -ftemplate-depth=2000 ...
 
# Clang
clang++ -ftemplate-depth=2000 ...

陷阱2:SFINAE误用(将在19.3详细讨论)

// 错误:会导致硬错误而非SFINAE
template <typename T>
struct BadEnableIf {
    // 当T没有value成员时,这里会编译失败
    static constexpr int value = T::value * 2;  // 硬错误!
};
 
// 正确:使用SFINAE
template <typename T, typename = std::enable_if_t<T::value > 0>>
struct GoodEnableIf {
    static constexpr int value = T::value * 2;
};

陷阱3:ODR(One Definition Rule)违规

// 错误:在不同翻译单元中定义不同的特化
// file1.cpp
template <>
struct MyTrait<int> { static const int value = 1; };
 
// file2.cpp  
template <>
struct MyTrait<int> { static const int value = 2; };  // ODR违规!

陷阱4:过度实例化

// 低效:每次调用都实例化新模板
for (int i = 0; i < 100; ++i) {
    process<i>();  // 错误!i必须是编译期常量
}
 
// 正确:使用运行时参数
template <typename T>
void process(int i);  // i是运行时参数

陷阱5:编译时间过长

// 危险:过度复杂的模板元编程
template <typename T>
struct Complex {
    typedef typename Complex<typename T::next>::type type;
    // 更多复杂操作...
};

解决方案

  • 使用extern template显式实例化
  • 将模板定义移到.cpp文件
  • 简化模板元编程逻辑

19.2.6 最佳实践

实践1:优先使用标准type_traits

// 不要重复造轮子
#include <type_traits>
 
// 使用标准库提供的特征
std::is_integral<T>::value
std::is_pointer<T>::value
std::remove_reference<T>::type
std::conditional<B, T, F>::type

实践2:使用别名模板简化语法

// C++11之前:冗长的typename
typename std::remove_reference<T>::type value;
 
// C++11及以后:使用别名模板
template <typename T>
using RemoveReference = typename std::remove_reference<T>::type;
 
RemoveReference<T> value;  // 更简洁!

实践3:使用constexpr函数替代元函数

// 旧方式:模板元编程
template <int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};
 
// 新方式:C++14 constexpr函数
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}
 
// 使用
constexpr int f5 = factorial(5);  // 编译期计算
int fn = factorial(n);  // 运行时计算(如果需要)

实践4:使用static_assert进行概念检查

template <typename T>
void process(T value) {
    static_assert(std::is_arithmetic<T>::value, 
                  "T must be an arithmetic type");
    // ...
}

实践5:文档化模板约束

/**
 * @brief 计算两点间距离
 * @tparam Point 必须满足:
 *   - 有x()和y()成员函数
 *   - 返回类型支持operator-和sqrt
 */
template <typename Point>
double distance(const Point& p1, const Point& p2);

本节要点

  1. 模板元编程的本质:利用C++模板系统在编译期执行计算和代码生成。

  2. 特化的两种形式

    • 全特化:为特定类型提供完全定制的实现
    • 偏特化:为一类类型(如所有指针)提供定制实现
  3. 递归模板实例化:通过模板递归实现编译期循环,需要明确的终止条件。

  4. type_traits的威力:类型特征是元编程的基础,CGAL大量使用它们来实现泛型算法。

  5. 编译期 vs 运行期:优先使用编译期计算来减少运行时开销,但要注意编译时间的平衡。

  6. 现代C++的建议:C++11/14/17提供了许多工具(constexpr、别名模板、变参模板)来简化元编程。


进一步阅读

  • 《C++ Templates: The Complete Guide》 (2nd Edition) by David Vandevoorde
  • 《Modern C++ Design》 by Andrei Alexandrescu
  • Boost.MPL文档:模板元编程库
  • CGAL文档:Kernel和STL_Extension模块的源代码