C/C++面试题(四):模板元编程和泛型编程
模板元编程(Template Metaprogramming, TMP) 和 泛型编程(Generic Programming) 是 C++ 中两个相关但不同的概念。它们都依赖于 C++ 的模板机制,但解决的问题和使用方式有所不同。下面我们来详细解释它们的区别和联系。
1. 泛型编程(Generic Programming)
泛型编程是一种编程范式,旨在编写与具体数据类型无关的通用代码。通过使用模板,泛型编程可以实现代码的复用性和类型安全性。
特点:
- 目标:编写通用的、可重用的代码。
- 核心工具:C++ 模板(template)。
- 典型应用:STL(标准模板库)中的容器(如 std::vector)和算法(如 std::sort)。
示例:
template
T add(T a, T b) {
return a + b;
}
int main() {
std::cout << add(3, 4) << std::endl; // 输出 7
std::cout << add(3.5, 4.2) << std::endl; // 输出 7.7
return 0;
}
- 这里的 add 函数是一个泛型函数,可以用于任何支持 + 操作的类型。
2. 模板元编程(Template Metaprogramming, TMP)
模板元编程是一种利用 C++ 模板机制在编译期进行计算和代码生成的编程技术。它的核心思想是将计算从运行时转移到编译时,从而生成高效的代码。
特点:
- 目标:在编译期进行计算、类型操作和代码生成。
- 核心工具:C++ 模板特化、递归模板、类型萃取(type traits)等。
- 典型应用:编译期计算、类型推导、代码生成。
示例:
(1)编译期计算
template
struct Factorial {
static const int value = N * Factorial::value;
};
template<>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << Factorial<5>::value << std::endl; // 输出 120(5!)
return 0;
}
- 这里的 Factorial 是一个模板元编程示例,它在编译期计算阶乘。
(2)类型萃取
#include
template
void print_type() {
if (std::is_integral::value) {
std::cout << "Integral type" << std::endl;
} else {
std::cout << "Non-integral type" << std::endl;
}
}
int main() {
print_type(); // 输出 "Integral type"
print_type(); // 输出 "Non-integral type"
return 0;
}
- 这里使用了 std::is_integral 来检查类型是否为整数类型。
3. 模板元编程 vs 泛型编程
特性 | 泛型编程(Generic Programming) | 模板元编程(Template Metaprogramming) |
目标 | 编写通用的、可重用的代码 | 在编译期进行计算和代码生成 |
核心工具 | 模板(template) | 模板特化、递归模板、类型萃取 |
运行时机 | 运行时 | 编译时 |
典型应用 | STL 容器和算法 | 编译期计算、类型推导、代码生成 |
代码复杂度 | 较低 | 较高 |
性能 | 运行时性能 | 编译期优化,减少运行时开销 |
4. 模板元编程的实际应用
(1)编译期计算
- 计算斐波那契数列、阶乘等。
- 示例:
template
struct Fibonacci {
static const int value = Fibonacci::value + Fibonacci::value;
};
template<> struct Fibonacci<0> { static const int value = 0; };
template<> struct Fibonacci<1> { static const int value = 1; };
int main() {
std::cout << Fibonacci<10>::value << std::endl; // 输出 55
return 0;
}
(2)类型萃取
- 检查类型特性(如是否为指针、是否为整数等)。
- 示例:
template
struct IsPointer {
static const bool value = false;
};
template
struct IsPointer {
static const bool value = true;
};
int main() {
std::cout << IsPointer::value << std::endl; // 输出 1(true)
std::cout << IsPointer::value << std::endl; // 输出 0(false)
return 0;
}
(3)代码生成
- 根据类型生成不同的代码。
- 示例:
template
void print(T value) {
if constexpr (std::is_integral_v) {
std::cout << "Integral: " << value << std::endl;
} else {
std::cout << "Non-integral: " << value << std::endl;
}
}
int main() {
print(42); // 输出 "Integral: 42"
print(3.14); // 输出 "Non-integral: 3.14"
return 0;
}
5. 总结
- 泛型编程 关注的是编写通用的、可重用的代码,主要通过模板实现。
- 模板元编程 关注的是在编译期进行计算和代码生成,利用模板特化、递归等技术实现。
- 两者都依赖于 C++ 的模板机制,但解决的问题和使用方式不同。