第20章 高级模板编程

模板元编程深度解析

1. 编译期计算与类型操作

模板元编程是C++中最强大的特性之一,它允许我们在编译期执行计算和类型操作,从而提高程序的性能和安全性。通过模板元编程,我们可以将运行时计算转移到编译期,减少运行时开销,同时获得更强的类型安全性。

1.1 编译期数值计算

编译期计算是模板元编程的核心应用之一,它允许我们在编译期计算常量值,避免运行时开销。通过递归模板和特化,我们可以实现各种复杂的编译期算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// 编译期计算斐波那契数列
template <unsigned N>
struct Fibonacci {
static constexpr unsigned value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
};

// 特化作为终止条件
template <>
struct Fibonacci<0> {
static constexpr unsigned value = 0;
};

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

// 编译期计算
template <unsigned N>
constexpr unsigned fibonacci_v = Fibonacci<N>::value;

// 使用编译期计算
static_assert(fibonacci_v<10> == 55, "Fibonacci calculation error");
static_assert(fibonacci_v<20> == 6765, "Fibonacci calculation error");

// 编译期计算阶乘
template <unsigned N>
struct Factorial {
static constexpr unsigned value = N * Factorial<N-1>::value;
};

template <>
struct Factorial<0> {
static constexpr unsigned value = 1;
};

template <unsigned N>
constexpr unsigned factorial_v = Factorial<N>::value;

// 编译期计算最大公约数
template <unsigned A, unsigned B>
struct GCD {
static constexpr unsigned value = GCD<B, A % B>::value;
};

template <unsigned A>
struct GCD<A, 0> {
static constexpr unsigned value = A;
};

template <unsigned A, unsigned B>
constexpr unsigned gcd_v = GCD<A, B>::value;

// 编译期计算平方根(整数)
template <unsigned N, unsigned L = 0, unsigned R = N>
struct Sqrt {
static constexpr unsigned mid = (L + R) / 2;
static constexpr unsigned value = mid * mid <= N && (mid + 1) * (mid + 1) > N
? mid
: (mid * mid < N ? Sqrt<N, mid + 1, R>::value : Sqrt<N, L, mid - 1>::value);
};

template <unsigned N>
constexpr unsigned sqrt_v = Sqrt<N>::value;

// 编译期位运算:计算二进制中1的个数
template <unsigned N>
struct PopCount {
static constexpr unsigned value = (N & 1) + PopCount<(N >> 1)>::value;
};

template <>
struct PopCount<0> {
static constexpr unsigned value = 0;
};

template <unsigned N>
constexpr unsigned popcount_v = PopCount<N>::value;

// 编译期测试
static_assert(factorial_v<5> == 120, "Factorial calculation error");
static_assert(gcd_v<48, 18> == 6, "GCD calculation error");
static_assert(sqrt_v<169> == 13, "Sqrt calculation error");
static_assert(popcount_v<0b101010> == 3, "PopCount calculation error");

1.2 编译期类型操作

模板元编程还允许我们在编译期执行复杂的类型操作,如类型转换、类型提取和类型组合。这些操作构成了模板元编程的核心工具集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// 类型特性:判断是否为指针类型
template <typename T>
struct is_pointer {
static constexpr bool value = false;
};

template <typename T>
struct is_pointer<T*> {
static constexpr bool value = true;
};

template <typename T>
constexpr bool is_pointer_v = is_pointer<T>::value;

// 类型特性:判断是否为左值引用
template <typename T>
struct is_lvalue_reference {
static constexpr bool value = false;
};

template <typename T>
struct is_lvalue_reference<T&> {
static constexpr bool value = true;
};

template <typename T>
constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;

// 类型特性:判断是否为右值引用
template <typename T>
struct is_rvalue_reference {
static constexpr bool value = false;
};

template <typename T>
struct is_rvalue_reference<T&&> {
static constexpr bool value = true;
};

template <typename T>
constexpr bool is_rvalue_reference_v = is_rvalue_reference<T>::value;

// 类型变换:移除指针修饰符
template <typename T>
struct remove_pointer {
using type = T;
};

template <typename T>
struct remove_pointer<T*> {
using type = typename remove_pointer<T>::type;
};

template <typename T>
using remove_pointer_t = typename remove_pointer<T>::type;

// 类型变换:移除引用修饰符
template <typename T>
struct remove_reference {
using type = T;
};

template <typename T>
struct remove_reference<T&> {
using type = T;
};

template <typename T>
struct remove_reference<T&&> {
using type = T;
};

template <typename T>
using remove_reference_t = typename remove_reference<T>::type;

// 类型变换:添加指针修饰符
template <typename T>
struct add_pointer {
using type = T*;
};

template <typename T>
using add_pointer_t = typename add_pointer<T>::type;

// 类型变换:添加左值引用
template <typename T>
struct add_lvalue_reference {
using type = T&;
};

// 特殊处理void类型
template <>
struct add_lvalue_reference<void> {
using type = void;
};

template <typename T>
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;

// 类型组合:创建元组类型
template <typename... Ts>
struct type_list {
static constexpr size_t size = sizeof...(Ts);
};

// 类型操作:向类型列表添加类型
template <typename List, typename T>
struct push_back;

template <typename... Ts, typename T>
struct push_back<type_list<Ts...>, T> {
using type = type_list<Ts..., T>;
};

template <typename List, typename T>
using push_back_t = typename push_back<List, T>::type;

// 类型操作:从类型列表移除最后一个类型
template <typename List>
struct pop_back;

template <typename T>
struct pop_back<type_list<T>> {
using type = type_list<>;
};

template <typename T, typename... Ts>
struct pop_back<type_list<T, Ts...>> {
using type = push_back_t<typename pop_back<type_list<Ts...>>::type, T>;
};

template <typename List>
using pop_back_t = typename pop_back<List>::type;

// 类型操作:连接两个类型列表
template <typename List1, typename List2>
struct concat;

template <typename... Ts>
struct concat<type_list<Ts...>, type_list<>> {
using type = type_list<Ts...>;
};

template <typename T, typename... Ts, typename... Us>
struct concat<type_list<Ts...>, type_list<T, Us...>> {
using type = concat_t<type_list<Ts..., T>, type_list<Us...>>;
};

template <typename List1, typename List2>
using concat_t = typename concat<List1, List2>::type;

// 类型提取:获取类型列表中的第N个类型
template <typename List, size_t N>
struct get_type;

template <typename T, typename... Ts, size_t N>
struct get_type<type_list<T, Ts...>, N> {
using type = typename get_type<type_list<Ts...>, N-1>::type;
};

template <typename T, typename... Ts>
struct get_type<type_list<T, Ts...>, 0> {
using type = T;
};

template <typename List, size_t N>
using get_type_t = typename get_type<List, N>::type;

// 类型提取:获取类型列表的长度
template <typename List>
struct list_size {
static constexpr size_t value = List::size;
};

template <typename List>
constexpr size_t list_size_v = list_size<List>::value;

// 使用类型操作
using MyTypes = type_list<int, double, std::string>;
static_assert(MyTypes::size == 3, "Type list size error");
static_assert(std::is_same_v<get_type_t<MyTypes, 0>, int>, "Type extraction error");
static_assert(std::is_same_v<get_type_t<MyTypes, 1>, double>, "Type extraction error");
static_assert(std::is_same_v<get_type_t<MyTypes, 2>, std::string>, "Type extraction error");

// 测试类型变换
using IntPtr = int*;
using Int = remove_pointer_t<IntPtr>;
static_assert(std::is_same_v<Int, int>, "Remove pointer error");

using IntRef = int&;
using Int2 = remove_reference_t<IntRef>;
static_assert(std::is_same_v<Int2, int>, "Remove reference error");

// 测试类型列表操作
using ExtendedTypes = push_back_t<MyTypes, bool>;
static_assert(ExtendedTypes::size == 4, "Push back error");
static_assert(std::is_same_v<get_type_t<ExtendedTypes, 3>, bool>, "Push back type error");

using ReducedTypes = pop_back_t<ExtendedTypes>;
static_assert(ReducedTypes::size == 3, "Pop back error");

using CombinedTypes = concat_t<MyTypes, type_list<float, char>>;
static_assert(CombinedTypes::size == 5, "Concat error");
static_assert(std::is_same_v<get_type_t<CombinedTypes, 3>, float>, "Concat type error");
static_assert(std::is_same_v<get_type_t<CombinedTypes, 4>, char>, "Concat type error");

2. 模板元编程高级技巧

2.1 SFINAE技术深度应用

SFINAE(Substitution Failure Is Not An Error)是模板元编程中的核心技术,它允许我们基于类型特性选择不同的模板重载。SFINAE的本质是当模板参数替换导致无效代码时,编译器会简单地忽略该重载,而不是报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// 使用SFINAE检测类型是否具有特定成员函数(使用std::void_t简化)
template <typename T, typename = void>
struct has_foo : std::false_type {};

template <typename T>
struct has_foo<T, std::void_t<decltype(std::declval<T>().foo())>> : std::true_type {};

template <typename T>
constexpr bool has_foo_v = has_foo<T>::value;

// 使用SFINAE检测类型是否具有特定成员变量
template <typename T, typename = void>
struct has_value : std::false_type {};

template <typename T>
struct has_value<T, std::void_t<decltype(std::declval<T>().value)>> : std::true_type {};

template <typename T>
constexpr bool has_value_v = has_value<T>::value;

// 使用SFINAE检测类型是否具有特定类型的成员
template <typename T, typename MemberType, typename = void>
struct has_member_type : std::false_type {};

template <typename T, typename MemberType>
struct has_member_type<T, MemberType, std::void_t<typename T::value_type>>
: std::is_same<typename T::value_type, MemberType> {};

template <typename T, typename MemberType>
constexpr bool has_member_type_v = has_member_type<T, MemberType>::value;

// 使用SFINAE检测类型是否可转换为特定类型
template <typename From, typename To, typename = void>
struct is_convertible : std::false_type {};

template <typename From, typename To>
struct is_convertible<From, To, std::void_t<decltype(static_cast<To>(std::declval<From>()))>>
: std::true_type {};

template <typename From, typename To>
constexpr bool is_convertible_v = is_convertible<From, To>::value;

// 使用SFINAE实现条件编译
template <typename T>
std::enable_if_t<has_foo_v<T>, void>
call_foo(T&& t) {
t.foo();
}

template <typename T>
std::enable_if_t<!has_foo_v<T>, void>
call_foo(T&& t) {
std::cout << "Type does not have foo() method" << std::endl;
}

// 使用SFINAE实现标签分发
template <typename T>
auto serialize(T&& t) -> std::enable_if_t<has_foo_v<T>, std::string> {
return "Serialized using foo()";
}

template <typename T>
auto serialize(T&& t) -> std::enable_if_t<!has_foo_v<T> && has_value_v<T>, std::string> {
return "Serialized using value member";
}

template <typename T>
auto serialize(T&& t) -> std::enable_if_t<!has_foo_v<T> && !has_value_v<T>, std::string> {
return "Default serialization";
}

// 使用SFINAE实现类型特性检测的组合
template <typename T>
struct is_iterable {
private:
template <typename U>
static auto test(U&& u) -> decltype(
std::begin(u),
std::end(u),
std::true_type{}
);

template <typename>
static std::false_type test(...);

public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};

template <typename T>
constexpr bool is_iterable_v = is_iterable<T>::value;

// 使用SFINAE实现函数重载选择
template <typename T>
auto print_impl(T&& t, std::true_type /* is_iterable */) {
std::cout << "[";
bool first = true;
for (auto&& elem : t) {
if (!first) std::cout << ", ";
std::cout << elem;
first = false;
}
std::cout << "]" << std::endl;
}

template <typename T>
auto print_impl(T&& t, std::false_type /* is_iterable */) {
std::cout << t << std::endl;
}

template <typename T>
void print(T&& t) {
print_impl(std::forward<T>(t), std::bool_constant<is_iterable_v<std::remove_cvref_t<T>>>{});
}

// 测试SFINAE功能
struct Foo {
void foo() {}
};

struct Value {
int value;
};

struct Complex {
using value_type = double;
void foo() {}
};

static_assert(has_foo_v<Foo>, "Foo should have foo()");
static_assert(!has_foo_v<Value>, "Value should not have foo()");
static_assert(has_value_v<Value>, "Value should have value member");
static_assert(!has_value_v<Foo>, "Foo should not have value member");
static_assert(has_member_type_v<Complex, double>, "Complex should have double value_type");
static_assert(is_convertible_v<int, double>, "int should be convertible to double");
static_assert(!is_convertible_v<double, int*>, "double should not be convertible to int*");
static_assert(is_iterable_v<std::vector<int>>, "vector should be iterable");
static_assert(!is_iterable_v<int>, "int should not be iterable");

2.2 编译期反射与类型遍历

编译期反射是模板元编程的高级应用,它允许我们在编译期获取类型的结构信息并进行遍历。虽然C++目前没有完整的编译期反射支持,但我们可以通过模板元编程实现有限的反射功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// 编译期类型列表遍历
template <typename... Ts>
struct type_list;

// 遍历类型列表并对每个类型执行操作
template <typename List, template <typename> typename Op>
struct for_each;

template <typename T, typename... Ts, template <typename> typename Op>
struct for_each<type_list<T, Ts...>, Op> {
static constexpr void apply() {
Op<T>::apply();
for_each<type_list<Ts...>, Op>::apply();
}
};

template <template <typename> typename Op>
struct for_each<type_list<>, Op> {
static constexpr void apply() {}
};

// 带索引的类型遍历
template <typename List, template <typename, size_t> typename Op, size_t Index = 0>
struct for_each_with_index;

template <typename T, typename... Ts, template <typename, size_t> typename Op, size_t Index>
struct for_each_with_index<type_list<T, Ts...>, Op, Index> {
static constexpr void apply() {
Op<T, Index>::apply();
for_each_with_index<type_list<Ts...>, Op, Index + 1>::apply();
}
};

template <template <typename, size_t> typename Op, size_t Index>
struct for_each_with_index<type_list<>, Op, Index> {
static constexpr void apply() {}
};

// 示例操作:打印类型信息
template <typename T>
struct print_type {
static constexpr void apply() {
// 注意:实际应用中需要使用编译期字符串操作
std::cout << "Type: " << typeid(T).name() << std::endl;
}
};

// 示例操作:带索引打印类型信息
template <typename T, size_t Index>
struct print_type_with_index {
static constexpr void apply() {
std::cout << "Type[" << Index << "]: " << typeid(T).name() << std::endl;
}
};

// 类型列表变换
template <typename List, template <typename> typename Transform>
struct transform;

template <typename T, typename... Ts, template <typename> typename Transform>
struct transform<type_list<T, Ts...>, Transform> {
using type = type_list<typename Transform<T>::type, typename transform<type_list<Ts...>, Transform>::type>;
};

template <template <typename> typename Transform>
struct transform<type_list<>, Transform> {
using type = type_list<>;
};

template <typename List, template <typename> typename Transform>
using transform_t = typename transform<List, Transform>::type;

// 类型过滤
template <typename List, template <typename> typename Predicate>
struct filter;

template <typename T, typename... Ts, template <typename> typename Predicate>
struct filter<type_list<T, Ts...>, Predicate> {
using rest = typename filter<type_list<Ts...>, Predicate>::type;
using type = std::conditional_t<Predicate<T>::value,
type_list<T, rest>,
rest
>;
};

template <template <typename> typename Predicate>
struct filter<type_list<>, Predicate> {
using type = type_list<>;
};

template <typename List, template <typename> typename Predicate>
using filter_t = typename filter<List, Predicate>::type;

// 类型谓词:判断是否为算术类型
template <typename T>
struct is_arithmetic : std::integral_constant<bool,
std::is_integral_v<T> || std::is_floating_point_v<T>
> {};

// 类型变换:添加const修饰符
template <typename T>
struct add_const {
using type = const T;
};

// 编译期类型哈希(简化版)
template <typename T>
struct type_hash {
private:
static constexpr size_t combine(size_t seed, size_t value) {
return seed ^ (value + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}

template <typename U>
static constexpr size_t hash() {
return combine(typeid(U).hash_code(), sizeof(U));
}

public:
static constexpr size_t value = hash<T>();
};

// 编译期类型映射(简化版)
template <typename Key, typename Value>
struct type_pair {
using key = Key;
using value = Value;
};

template <typename... Pairs>
struct type_map {
static constexpr size_t size = sizeof...(Pairs);
};

// 从类型映射中查找值类型
template <typename Map, typename Key>
struct lookup;

template <typename Key, typename Value, typename... Pairs>
struct lookup<type_map<type_pair<Key, Value>, Pairs...>, Key> {
using type = Value;
};

template <typename Key, typename Value, typename... Pairs, typename LookupKey>
struct lookup<type_map<type_pair<Key, Value>, Pairs...>, LookupKey> {
using type = typename lookup<type_map<Pairs...>, LookupKey>::type;
};

template <typename Map, typename Key>
using lookup_t = typename lookup<Map, Key>::type;

// 使用编译期反射功能
using MyTypes = type_list<int, double, std::string, bool, float>;

// 遍历类型列表
std::cout << "=== Type List Traversal ===" << std::endl;
for_each<MyTypes, print_type>::apply();

// 带索引遍历类型列表
std::cout << "=== Type List Traversal with Index ===" << std::endl;
for_each_with_index<MyTypes, print_type_with_index>::apply();

// 变换类型列表
using ConstTypes = transform_t<MyTypes, add_const>;
std::cout << "=== Transformed Type List (const) ===" << std::endl;
for_each<ConstTypes, print_type>::apply();

// 过滤类型列表
using ArithmeticTypes = filter_t<MyTypes, is_arithmetic>;
std::cout << "=== Filtered Type List (arithmetic) ===" << std::endl;
for_each<ArithmeticTypes, print_type>::apply();

// 使用类型映射
using MyTypeMap = type_map<
type_pair<int, std::string>,
type_pair<double, int>,
type_pair<std::string, bool>
>;

using MappedType1 = lookup_t<MyTypeMap, int>;
static_assert(std::is_same_v<MappedType1, std::string>, "Type map lookup error");

using MappedType2 = lookup_t<MyTypeMap, double>;
static_assert(std::is_same_v<MappedType2, int>, "Type map lookup error");

// 测试类型哈希
static_assert(type_hash<int>::value != type_hash<double>::value, "Type hash collision");
static_assert(type_hash<std::string>::value != type_hash<int>::value, "Type hash collision");

2.3 可变参数模板的高级应用

可变参数模板是C++11引入的强大特性,它允许我们处理任意数量的模板参数。通过递归展开和折叠表达式,我们可以实现各种复杂的模板操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// 可变参数模板的递归展开
template <typename T>
void print_single(T&& t) {
std::cout << std::forward<T>(t) << std::endl;
}

template <typename T, typename... Args>
void print(T&& first, Args&&... rest) {
print_single(std::forward<T>(first));
print(std::forward<Args>(rest)...);
}

// 基本情况
template <>
void print() {}

// 使用折叠表达式(C++17+)
template <typename... Args>
void print_fold(Args&&... args) {
(std::cout << ... << std::forward<Args>(args)) << std::endl;
}

// 带分隔符的折叠表达式
template <typename... Args>
void print_with_separator(Args&&... args) {
const char* sep = "";
((std::cout << sep << std::forward<Args>(args)), sep = ", ")...;
std::cout << std::endl;
}

// 可变参数模板的类型转换
template <typename Target, typename... Args>
auto convert_all(Args&&... args) {
return std::make_tuple(static_cast<Target>(std::forward<Args>(args))...);
}

// 可变参数模板的类型推导
namespace detail {
template <typename T, typename... Args>
struct first_type {
using type = T;
};
}

template <typename... Args>
using first_type_t = typename detail::first_type<Args...>::type;

// 可变参数模板的类型计数
template <typename... Args>
struct count_types {
static constexpr size_t value = sizeof...(Args);
};

template <typename... Args>
constexpr size_t count_types_v = count_types<Args...>::value;

// 可变参数模板的类型检查
namespace detail {
template <typename T, typename... Args>
struct are_all_same {
static constexpr bool value = (std::is_same_v<T, Args> && ...);
};
}

template <typename... Args>
struct are_all_same {
static constexpr bool value = detail::are_all_same<first_type_t<Args...>, Args...>::value;
};

template <typename... Args>
constexpr bool are_all_same_v = are_all_same<Args...>::value;

// 可变参数模板的最大值计算
namespace detail {
template <typename T>
constexpr T max_impl(T value) {
return value;
}

template <typename T, typename... Args>
constexpr T max_impl(T first, Args... rest) {
T next = max_impl(rest...);
return first > next ? first : next;
}
}

template <typename T, typename... Args>
constexpr T max(T first, Args... rest) {
static_assert((std::is_same_v<T, Args> && ...), "All arguments must be of the same type");
return detail::max_impl(first, rest...);
}

// 可变参数模板的元组操作
namespace detail {
template <typename F, typename Tuple, size_t... Is>
constexpr auto apply_impl(F&& f, Tuple&& tuple, std::index_sequence<Is...>) {
return std::forward<F>(f)(std::get<Is>(std::forward<Tuple>(tuple))...);
}
}

template <typename F, typename Tuple>
constexpr auto apply(F&& f, Tuple&& tuple) {
return detail::apply_impl(
std::forward<F>(f),
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<Tuple>>>()
);
}

// 可变参数模板的工厂函数
template <typename T, typename... Args>
auto make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// 可变参数模板的类型列表生成
template <typename... Args>
struct type_list_from_args {
using type = type_list<Args...>;
};

template <typename... Args>
using type_list_from_args_t = typename type_list_from_args<Args...>::type;

// 可变参数模板的类型过滤(运行时)
template <typename Predicate, typename... Args>
auto filter_args(Predicate&& pred, Args&&... args) {
return std::tuple_cat(
[&]<typename T>(T&& arg) {
if (pred(arg)) {
return std::make_tuple(std::forward<T>(arg));
} else {
return std::tuple<>{};
}
}(std::forward<Args>(args))...
);
}

// 可变参数模板的类型映射(运行时)
template <typename F, typename... Args>
auto map_args(F&& f, Args&&... args) {
return std::make_tuple(
std::forward<F>(f)(std::forward<Args>(args))...
);
}

// 测试可变参数模板功能
static_assert(count_types_v<int, double, std::string> == 3, "Count types error");
static_assert(are_all_same_v<int, int, int>, "Are all same error");
static_assert(!are_all_same_v<int, double, int>, "Are all same error");
static_assert(max(1, 2, 3, 4, 5) == 5, "Max error");
static_assert(max(1.5, 2.7, 0.9) == 2.7, "Max error");

// 使用apply函数
auto tuple = std::make_tuple(1, 2.5, "hello");
auto result = apply([](auto a, auto b, auto c) {
return a + static_cast<int>(b) + std::string(c).length();
}, tuple);
static_assert(std::is_same_v<decltype(result), int>, "Apply result type error");

// 使用工厂函数
auto ptr = make_unique<std::vector<int>>(10, 42);
static_assert(std::is_same_v<decltype(ptr), std::unique_ptr<std::vector<int>>>, "Make unique error");

// 使用类型列表生成
using MyTypes = type_list_from_args_t<int, double, bool, std::string>;
static_assert(MyTypes::size == 4, "Type list from args error");

// 使用参数过滤
auto filtered = filter_args([](auto x) { return x > 2; }, 1, 3, 5, 2, 4);
static_assert(std::tuple_size_v<decltype(filtered)> == 3, "Filter args error");

// 使用参数映射
auto mapped = map_args([](auto x) { return x * 2; }, 1, 2, 3, 4);
static_assert(std::tuple_size_v<decltype(mapped)> == 4, "Map args error");

3. 模板编程的性能优化

3.1 模板代码膨胀与优化

模板代码膨胀是模板编程中常见的问题,它会导致可执行文件变大、编译时间变长。以下是一些有效的优化策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// 使用类型擦除减少代码膨胀
template <typename T>
class TypeErasedContainer {
private:
struct Concept {
virtual ~Concept() = default;
virtual void push_back(const void*) = 0;
virtual void* get(size_t) = 0;
virtual const void* get(size_t) const = 0;
};

template <typename U>
struct Model : Concept {
std::vector<U> data;

void push_back(const void* value) override {
data.push_back(*static_cast<const U*>(value));
}

void* get(size_t index) override {
return &data[index];
}

const void* get(size_t index) const override {
return &data[index];
}
};

std::unique_ptr<Concept> impl;

public:
template <typename U>
TypeErasedContainer() : impl(std::make_unique<Model<U>>()) {}

template <typename U>
void push_back(U value) {
static_cast<Model<U>*>(impl.get())->push_back(&value);
}

template <typename U>
U& get(size_t index) {
return *static_cast<U*>(static_cast<Model<U>*>(impl.get())->get(index));
}

template <typename U>
const U& get(size_t index) const {
return *static_cast<const U*>(static_cast<Model<U>*>(impl.get())->get(index));
}
};

// 使用模板特化减少代码膨胀
template <typename T>
class Math {
public:
static T sqrt(T x) {
return std::sqrt(x);
}
};

// 为常用类型提供特化版本
template <>
class Math<float> {
public:
static float sqrt(float x) {
return std::sqrtf(x); // 使用float专用函数
}
};

template <>
class Math<double> {
public:
static double sqrt(double x) {
return std::sqrt(x); // 使用double专用函数
}
};

// 使用基类提取公共代码
template <typename T>
class VectorBase {
protected:
T* data;
size_t size;
size_t capacity;

public:
VectorBase(size_t initialCapacity = 0)
: data(nullptr), size(0), capacity(0) {
if (initialCapacity > 0) {
reserve(initialCapacity);
}
}

~VectorBase() {
delete[] data;
}

void reserve(size_t newCapacity) {
if (newCapacity > capacity) {
T* newData = new T[newCapacity];
for (size_t i = 0; i < size; ++i) {
newData[i] = data[i];
}
delete[] data;
data = newData;
capacity = newCapacity;
}
}

size_t getSize() const { return size; }
size_t getCapacity() const { return capacity; }
};

// 模板派生类只处理类型相关的操作
template <typename T>
class Vector : public VectorBase<T> {
public:
Vector(size_t initialCapacity = 0) : VectorBase<T>(initialCapacity) {}

void push_back(const T& value) {
if (this->size == this->capacity) {
this->reserve(this->capacity == 0 ? 1 : this->capacity * 2);
}
this->data[this->size++] = value;
}

T& operator[](size_t index) {
return this->data[index];
}

const T& operator[](size_t index) const {
return this->data[index];
}
};

// 使用外部多态减少代码膨胀
class Any {
private:
struct Concept {
virtual ~Concept() = default;
virtual Concept* clone() const = 0;
virtual std::type_index type() const = 0;
};

template <typename T>
struct Model : Concept {
T value;

Model(const T& v) : value(v) {}

Concept* clone() const override {
return new Model<T>(value);
}

std::type_index type() const override {
return std::type_index(typeid(T));
}
};

Concept* impl;

public:
template <typename T>
Any(const T& value) : impl(new Model<T>(value)) {}

Any(const Any& other) : impl(other.impl->clone()) {}

Any& operator=(const Any& other) {
if (this != &other) {
delete impl;
impl = other.impl->clone();
}
return *this;
}

~Any() {
delete impl;
}

template <typename T>
T* as() {
if (impl->type() == std::type_index(typeid(T))) {
return &static_cast<Model<T>*>(impl)->value;
}
return nullptr;
}
};

// 使用模板参数分离减少膨胀
template <typename Policy>
class Algorithm {
private:
Policy policy;

public:
Algorithm(Policy p = Policy()) : policy(std::move(p)) {}

template <typename T>
void process(T& data) {
policy.process(data);
}
};

// 策略类可以是非模板的
struct DefaultPolicy {
template <typename T>
void process(T& data) {
// 默认处理逻辑
}
};

struct OptimizedPolicy {
template <typename T>
void process(T& data) {
// 优化的处理逻辑
}
};

3.2 编译时间优化

编译时间是模板编程中的另一个重要考虑因素,尤其是在大型项目中。以下是一些有效的优化策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// 1. 预编译头文件
// 将常用模板定义放入预编译头文件
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <memory>

// 2. 显式实例化
template <typename T>
class MyTemplate {
public:
void process() {
// 实现
}
};

// 显式实例化声明(.h文件)
extern template class MyTemplate<int>;
extern template class MyTemplate<double>;
extern template class MyTemplate<std::string>;

// 显式实例化定义(.cpp文件)
template class MyTemplate<int>;
template class MyTemplate<double>;
template class MyTemplate<std::string>;

// 3. 模板拆分
// 将模板声明和定义分离
// mytemplate.h
template <typename T>
class MyTemplate {
public:
void process();
};

// mytemplate.tpp
#include "mytemplate.h"

template <typename T>
void MyTemplate<T>::process() {
// 实现
}

// 使用时包含
#include "mytemplate.h"
#include "mytemplate.tpp"

// 4. 减少模板嵌套深度
template <typename T>
class DeeplyNested {
private:
// 避免过深的模板嵌套
std::vector<T> data;

public:
void add(const T& value) {
data.push_back(value);
}
};

// 5. 使用模板参数默认值减少重复实例化
template <typename T, typename Allocator = std::allocator<T>>
class MyVector {
private:
std::vector<T, Allocator> data;

public:
void push_back(const T& value) {
data.push_back(value);
}
};

// 6. 避免在头文件中使用复杂模板表达式
// 不好的做法
// header.h
template <typename T>
class BadExample {
public:
// 复杂的模板表达式在头文件中
auto process() -> decltype(std::declval<T>().foo()) {
return T().foo();
}
};

// 好的做法
// header.h
template <typename T>
class GoodExample {
public:
// 简单的接口
void process();
};

// implementation.tpp
#include "header.h"

template <typename T>
void GoodExample<T>::process() {
// 复杂的实现放在这里
auto result = T().foo();
// 处理结果
}

// 7. 使用编译防火墙(Pimpl模式)
template <typename T>
class PimplExample {
private:
class Impl;
std::unique_ptr<Impl> impl;

public:
PimplExample();
~PimplExample();
void process();
};

// implementation.cpp
template <typename T>
class PimplExample<T>::Impl {
public:
void doProcess() {
// 复杂的实现
}
};

template <typename T>
PimplExample<T>::PimplExample() : impl(std::make_unique<Impl>()) {}

template <typename T>
PimplExample<T>::~PimplExample() = default;

template <typename T>
void PimplExample<T>::process() {
impl->doProcess();
}

// 显式实例化
template class PimplExample<int>;
template class PimplExample<double>;

// 8. 使用模块化设计减少依赖
// 模块A:基础功能
template <typename T>
class ModuleA {
public:
void basicFunction() {
// 基础功能
}
};

// 模块B:依赖模块A的高级功能
template <typename T>
class ModuleB {
private:
ModuleA<T> moduleA;

public:
void advancedFunction() {
moduleA.basicFunction();
// 高级功能
}
};

3.3 运行时性能优化

模板编程也可以通过一些技巧来提高运行时性能,充分发挥C++的性能优势:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// 1. 内联展开优化
template <typename T>
inline T maximum(T a, T b) {
return a > b ? a : b;
}

// 强制内联提示
template <typename T>
__attribute__((always_inline)) // GCC
inline T minimum(T a, T b) {
return a < b ? a : b;
}

// 2. 编译期计算优化
template <size_t N>
struct CompileTimeArray {
static constexpr size_t size = N;
int data[N];

constexpr CompileTimeArray() : data() {
for (size_t i = 0; i < N; ++i) {
data[i] = i * i;
}
}
};

// 编译期初始化数组
constexpr auto lookupTable = CompileTimeArray<1000>{};

// 编译期计算的阶乘表
template <size_t N>
struct FactorialTable {
static constexpr size_t size = N;
unsigned long long data[N];

constexpr FactorialTable() : data() {
data[0] = 1;
for (size_t i = 1; i < N; ++i) {
data[i] = data[i-1] * i;
}
}
};

constexpr auto factorialTable = FactorialTable<20>{};

// 3. 内存布局优化
template <typename T>
class OptimizedContainer {
private:
// 按大小排序成员,减少内存对齐开销
double value; // 8字节
int counter; // 4字节
char flag; // 1字节
// 总大小:13字节,对齐到16字节

public:
// 实现
};

// 4. 类型特化优化
template <typename T>
class MathOperations {
public:
static T sqrt(T value) {
return std::sqrt(value);
}
};

// 为int类型提供特化版本,使用整数平方根算法
template <>
class MathOperations<int> {
public:
static int sqrt(int value) {
if (value < 0) return 0;
int result = 0;
int bit = 1 << 30;

while (bit > value) {
bit >>= 2;
}

while (bit != 0) {
if (value >= result + bit) {
value -= result + bit;
result = (result >> 1) + bit;
} else {
result >>= 1;
}
bit >>= 2;
}

return result;
}
};

// 5. SIMD优化的模板
template <typename T>
class SIMDOperations {
public:
static void multiply_add(const T* a, const T* b, T* result, size_t size) {
for (size_t i = 0; i < size; ++i) {
result[i] = a[i] * b[i] + result[i];
}
}
};

// 为float类型提供SIMD优化版本
#ifdef __AVX2__
template <>
class SIMDOperations<float> {
public:
static void multiply_add(const float* a, const float* b, float* result, size_t size) {
size_t i = 0;
for (; i + 7 < size; i += 8) {
__m256 va = _mm256_loadu_ps(&a[i]);
__m256 vb = _mm256_loadu_ps(&b[i]);
__m256 vr = _mm256_loadu_ps(&result[i]);
vr = _mm256_fmadd_ps(va, vb, vr);
_mm256_storeu_ps(&result[i], vr);
}
// 处理剩余元素
for (; i < size; ++i) {
result[i] = a[i] * b[i] + result[i];
}
}
};
#endif

// 6. 分支预测优化
template <typename T>
class BranchOptimized {
public:
static T max(const std::vector<T>& values) {
if (values.empty()) return T{};

T current_max = values[0];
// 预测分支总是不 taken
for (size_t i = 1; i < values.size(); ++i) {
if (values[i] > current_max) {
current_max = values[i];
}
}
return current_max;
}
};

// 7. 缓存友好的数据结构
template <typename T, size_t BlockSize = 64 / sizeof(T)>
class CacheFriendlyArray {
private:
std::vector<T> data;

public:
CacheFriendlyArray(size_t size) : data(size) {}

// 按缓存块顺序访问
void process() {
for (size_t block = 0; block < data.size(); block += BlockSize) {
for (size_t offset = 0; offset < BlockSize && block + offset < data.size(); ++offset) {
// 处理 data[block + offset]
data[block + offset] *= 2;
}
}
}
};

// 8. 模板参数化的性能策略
template <typename T, bool EnableSIMD = false>
class PerformanceOptimized {
public:
static void process(T* data, size_t size) {
// 通用实现
for (size_t i = 0; i < size; ++i) {
data[i] = std::sin(data[i]) * std::cos(data[i]);
}
}
};

// SIMD优化版本
#ifdef __AVX2__
template <typename T>
class PerformanceOptimized<T, true> {
public:
static void process(T* data, size_t size) {
// SIMD优化实现
if constexpr (std::is_same_v<T, float>) {
size_t i = 0;
for (; i + 7 < size; i += 8) {
__m256 v = _mm256_loadu_ps(&data[i]);
v = _mm256_mul_ps(_mm256_sin_ps(v), _mm256_cos_ps(v));
_mm256_storeu_ps(&data[i], v);
}
// 处理剩余元素
for (; i < size; ++i) {
data[i] = std::sin(data[i]) * std::cos(data[i]);
}
} else {
// 其他类型的通用实现
for (size_t i = 0; i < size; ++i) {
data[i] = std::sin(data[i]) * std::cos(data[i]);
}
}
}
};
#endif

// 9. 编译期多态代替运行时多态
template <typename Strategy>
class Algorithm {
private:
Strategy strategy;

public:
Algorithm(Strategy s = Strategy()) : strategy(std::move(s)) {}

template <typename T>
void process(T& data) {
// 编译期分发,无虚函数调用开销
strategy.process(data);
}
};

struct FastStrategy {
template <typename T>
void process(T& data) {
// 快速但可能不那么准确的实现
}
};

struct AccurateStrategy {
template <typename T>
void process(T& data) {
// 准确但可能较慢的实现
}
};

// 10. 编译期条件编译
template <typename T>
class ConditionalImplementation {
public:
static void process(T value) {
if constexpr (std::is_integral_v<T>) {
// 整数类型的实现
std::cout << "Processing integer: " << value << std::endl;
} else if constexpr (std::is_floating_point_v<T>) {
// 浮点类型的实现
std::cout << "Processing floating point: " << value << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
// 字符串类型的实现
std::cout << "Processing string: " << value << std::endl;
} else {
// 其他类型的实现
std::cout << "Processing other type" << std::endl;
}
}
};

4. 现代C++中的模板特性

4.1 C++20 概念(Concepts)

概念是C++20引入的重要特性,它允许我们为模板参数定义明确的约束,提高代码的可读性和错误消息的清晰度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <concepts>

// 自定义概念
template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

template <typename T>
concept Sortable = requires(T a, T b) {
{ a < b } -> std::convertible_to<bool>;
{ a > b } -> std::convertible_to<bool>;
{ a == b } -> std::convertible_to<bool>;
};

// 使用概念约束模板参数
template <Numeric T>
T sum(T a, T b) {
return a + b;
}

template <Sortable T>
void sort(std::vector<T>& values) {
std::sort(values.begin(), values.end());
}

// 组合概念
template <typename T>
concept NumericAndSortable = Numeric<T> && Sortable<T>;

template <NumericAndSortable T>
T find_min(const std::vector<T>& values) {
return *std::min_element(values.begin(), values.end());
}

4.2 C++20 模板Lambda

模板Lambda是C++20引入的另一个重要特性,它允许我们在Lambda表达式中使用模板参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 模板Lambda
auto add = []<typename T>(T a, T b) {
return a + b;
};

// 使用不同类型
std::cout << "Add integers: " << add(1, 2) << std::endl;
std::cout << "Add doubles: " << add(1.5, 2.5) << std::endl;
std::cout << "Add strings: " << add(std::string("Hello"), std::string(" World")) << std::endl;

// 带约束的模板Lambda
auto multiply = []<typename T>(T a, T b) requires std::is_arithmetic_v<T> {
return a * b;
};

// 可变参数模板Lambda
auto print = []<typename... Args>(Args&&... args) {
(std::cout << ... << std::forward<Args>(args)) << std::endl;
};

print("The answer is ", 42, ", and pi is ", 3.14159);

4.3 C++17 折叠表达式

折叠表达式是C++17引入的特性,它简化了可变参数模板的处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 基本折叠表达式
template <typename... Args>
void print(Args&&... args) {
(std::cout << ... << std::forward<Args>(args)) << std::endl;
}

// 带分隔符的折叠表达式
template <typename... Args>
void print_with_separator(Args&&... args) {
const char* sep = "";
((std::cout << sep << std::forward<Args>(args)), sep = ", ")...;
std::cout << std::endl;
}

// 算术运算折叠表达式
template <typename... Args>
auto sum(Args&&... args) {
return (std::forward<Args>(args) + ...);
}

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

4.4 C++17 类模板参数推导

类模板参数推导是C++17引入的特性,它允许编译器从构造函数参数推导类模板参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 类模板
template <typename T>
class MyContainer {
private:
std::vector<T> data;

public:
MyContainer(std::initializer_list<T> init) : data(init) {}

void push_back(const T& value) {
data.push_back(value);
}

size_t size() const {
return data.size();
}
};

// 使用类模板参数推导
MyContainer c1 = {1, 2, 3}; // 推导为 MyContainer<int>
MyContainer c2 = {1.5, 2.5, 3.5}; // 推导为 MyContainer<double>
MyContainer c3 = {"hello", "world"}; // 推导为 MyContainer<const char*>

5. 模板编程的最佳实践

5.1 模板设计原则

  1. 单一职责原则:每个模板应该只负责一个功能,避免过度复杂的模板设计。

  2. 可测试性:确保模板可以被有效测试,为常用类型提供测试用例。

  3. 可扩展性:设计灵活的模板接口,允许用户通过特化或继承进行扩展。

  4. 性能考虑:避免不必要的模板实例化,为常用类型提供特化版本。

  5. 错误处理:使用static_assert和概念提供清晰的编译期错误消息。

5.2 模板编程技巧

  1. 标签分发:使用标签类型选择不同的实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    struct fast_tag {};
    struct safe_tag {};

    template <typename T>
    void process(T value, fast_tag) {
    // 快速实现
    }

    template <typename T>
    void process(T value, safe_tag) {
    // 安全实现
    }

    template <typename T>
    void process(T value) {
    if constexpr (std::is_integral_v<T>) {
    process(value, fast_tag{});
    } else {
    process(value, safe_tag{});
    }
    }
  2. CRTP:使用奇异递归模板模式实现静态多态。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template <typename Derived>
    class Base {
    public:
    void interface() {
    static_cast<Derived*>(this)->implementation();
    }
    };

    class Derived : public Base<Derived> {
    public:
    void implementation() {
    std::cout << "Derived implementation" << std::endl;
    }
    };
  3. 类型 traits:使用类型特性获取编译期类型信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    template <typename T>
    struct is_container {
    private:
    template <typename C>
    static auto test(C&& c) -> decltype(
    std::begin(c),
    std::end(c),
    std::true_type{}
    );

    template <typename>
    static std::false_type test(...);

    public:
    static constexpr bool value = decltype(test(std::declval<T>()))::value;
    };

    template <typename T>
    constexpr bool is_container_v = is_container<T>::value;
  4. 完美转发:使用完美转发保持值类别。

    1
    2
    3
    4
    template <typename T, typename... Args>
    T create(Args&&... args) {
    return T(std::forward<Args>(args)...);
    }

5.3 模板的文档和注释

  1. 模板参数说明:详细说明每个模板参数的用途和约束。

  2. 使用示例:提供模板的使用示例,包括常见用例和边缘情况。

  3. 性能注意事项:说明模板的性能特性和优化建议。

  4. 兼容性说明:说明模板的C++标准要求和编译器兼容性。

6. 模板编程的常见错误和陷阱

6.1 模板参数推导失败

模板参数推导失败是模板编程中最常见的错误之一,以下是一些常见原因和解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 错误:无法推导T的类型
template<typename T>
void print(T a, T b) {
std::cout << a << " " << b << std::endl;
}

print(10, 3.14); // 一个是int,一个是double

// 解决方案1:显式指定模板参数
print<double>(10, 3.14);

// 解决方案2:使用两个模板参数
template<typename T1, typename T2>
void print(T1 a, T2 b) {
std::cout << a << " " << b << std::endl;
}

6.2 模板实例化错误

模板实例化错误通常发生在模板代码尝试使用类型不支持的操作时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 错误:当T不支持<运算符时会失败
template<typename T>
T max(T a, T b) {
return a > b ? a : b;
}

// 解决方案:使用概念约束模板参数
#include <concepts>

template <typename T>
concept Comparable = requires(T a, T b) {
{ a < b } -> std::convertible_to<bool>;
};

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

6.3 模板特化顺序

模板特化的顺序很重要,特化版本应该在使用前定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 错误:特化模板在使用后定义
template<typename T>
class MyClass { /* ... */ };

// 使用模板
MyClass<int> obj;

// 特化模板
template<>
class MyClass<int> { /* ... */ };

// 正确:先定义特化模板,再使用
template<typename T>
class MyClass { /* ... */ };

// 特化模板
template<>
class MyClass<int> { /* ... */ };

// 使用模板
MyClass<int> obj;

6.4 模板参数依赖

依赖模板参数的名称需要使用typename关键字:

1
2
3
4
5
6
7
8
9
10
11
// 错误:依赖模板参数的名称需要使用typename
template <typename T>
void func() {
T::type x; // 错误:需要使用typename
}

// 正确:使用typename
template <typename T>
void func() {
typename T::type x;
}

6.5 模板参数包展开

可变参数模板的参数包展开需要使用正确的语法:

1
2
3
4
5
6
7
8
9
10
11
// 错误:可变参数模板的参数包展开错误
template<typename... Args>
void print(Args... args) {
std::cout << args...; // 错误:需要使用折叠表达式或递归
}

// 正确:使用折叠表达式(C++17+)
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << std::endl;
}

7. 模板编程的应用场景

模板编程在C++中有广泛的应用场景,以下是一些常见的例子:

7.1 容器库

标准模板库(STL)中的容器是模板编程的典型应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// STL容器
std::vector<int> numbers;
std::map<std::string, int> counts;
std::unordered_set<double> uniqueValues;

// 自定义容器
template <typename T>
class MyVector {
private:
T* data;
size_t size;
size_t capacity;

public:
MyVector() : data(nullptr), size(0), capacity(0) {}

void push_back(const T& value) {
if (size == capacity) {
reserve(capacity == 0 ? 1 : capacity * 2);
}
data[size++] = value;
}

void reserve(size_t newCapacity) {
if (newCapacity > capacity) {
T* newData = new T[newCapacity];
for (size_t i = 0; i < size; ++i) {
newData[i] = data[i];
}
delete[] data;
data = newData;
capacity = newCapacity;
}
}

// 其他方法...
};

7.2 算法库

STL中的算法也是模板编程的重要应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// STL算法
std::sort(numbers.begin(), numbers.end());
std::find(numbers.begin(), numbers.end(), 42);
std::for_each(numbers.begin(), numbers.end(), [](int n) { std::cout << n << " "; });

// 自定义算法
template <typename Iterator, typename Predicate>
Iterator find_if(Iterator begin, Iterator end, Predicate pred) {
for (; begin != end; ++begin) {
if (pred(*begin)) {
return begin;
}
}
return end;
}

7.3 智能指针

智能指针是模板编程的另一个重要应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// STL智能指针
std::unique_ptr<int> ptr1(new int(42));
std::shared_ptr<std::string> ptr2 = std::make_shared<std::string>("hello");

// 自定义智能指针
template <typename T>
class UniquePtr {
private:
T* ptr;

public:
explicit UniquePtr(T* p = nullptr) : ptr(p) {}

~UniquePtr() {
delete ptr;
}

UniquePtr(const UniquePtr&) = delete;
UniquePtr& operator=(const UniquePtr&) = delete;

UniquePtr(UniquePtr&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr;
}

UniquePtr& operator=(UniquePtr&& other) noexcept {
if (this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}

T& operator*() const {
return *ptr;
}

T* operator->() const {
return ptr;
}

T* get() const {
return ptr;
}
};

7.4 函数对象和Lambda

函数对象和Lambda表达式也是模板编程的重要应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 函数对象
template <typename T>
class Comparator {
public:
bool operator()(const T& a, const T& b) const {
return a < b;
}
};

// 使用函数对象
std::sort(numbers.begin(), numbers.end(), Comparator<int>());

// Lambda表达式(底层也是模板实现)
auto compare = [](const auto& a, const auto& b) {
return a < b;
};

std::sort(numbers.begin(), numbers.end(), compare);

总结

模板是C++中实现泛型编程的强大工具,它允许我们编写与类型无关的代码,提高代码的重用性和灵活性。本章介绍了:

  1. 模板的基本概念:函数模板和类模板
  2. 模板特化:全特化和偏特化
  3. 可变参数模板:处理任意数量的参数
  4. 模板元编程:在编译时执行计算
  5. C++20模板增强:模板lambda、概念、requires表达式
  6. 模板编程最佳实践:命名约定、代码组织、性能考虑
  7. 常见错误:模板参数推导失败、实例化错误等
  8. 应用场景:容器、算法、智能指针等

模板编程是C++的高级特性,掌握它需要一定的实践经验。通过不断学习和使用模板,你将能够编写更加灵活、高效、可重用的C++代码。