相较于宏,C++更推荐使用模板编程,因为它们提供了更好的类型安全、更清晰的语法和更易于调试的代码
1.模板函数
语法
cpp
template <typename T>
void function(T param) {
// 函数体,使用T作为类型参数
}
例子
cpp
#include <iostream>
using namespace std;
// 模板函数,用于计算两个值的和
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int intResult = add(10, 20); // 自动推导T为int
double doubleResult = add(10.5, 20.5); // 自动推导T为double
cout << "Sum of ints: " << intResult << endl;
cout << "Sum of doubles: " << doubleResult << endl;
// 也可以显式指定模板参数类型
long longResult = add<long>(100, 200);//指定为int
cout << "Sum of longs: " << longResult << endl;
system("pause");
return 0;
}
模板函数特化: 模板函数还可以进行特化,为特定类型提供特定的实现。
例子
cpp
#include <iostream>
using namespace std;
// 通用模板函数
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
// 特化模板函数,针对整数类型
template <>
int maximum<int>(int a, int b) {
cout << "Maximum of two integers: " << (a > b ? a : b) << endl;
return (a > b) ? a : b;
}
int main() {
int i = maximum(10, 20); // 使用特化版本
double d = maximum(3.14, 2.72); // 使用通用模板版本
cout << "Max int: " << i << endl;
cout << "Max double: " << d << endl;
system("pause");
return 0;
}
2.模板类
语法
cpp
template <typename T>
class MyClass {
public:
T member; // 使用模板参数T作为类的成员变量类型
void function(T param) {
// 使用模板参数T作为函数参数类型
}
};
例子
cpp
#include <iostream>
using namespace std;
// 模板类Box的定义
template <typename T>
class Box {
private:
T contents; // 盒子里存储的对象,类型由模板参数T决定
public:
// 构造函数,用于初始化盒子里的对象
Box(const T& value) : contents(value) {}
// 成员函数,用于获取盒子里的对象
T getContents() const {
return contents;
}
// 成员函数,用于设置盒子里的对象
void setContents(const T& value) {
contents = value;
}
};
int main() {
// 创建一个存储整数的盒子
Box<int> intBox(10);
cout << "The Box contains: " << intBox.getContents() << endl;
// 创建一个存储字符串的盒子
Box<string> stringBox("Hello, World!");
cout << "The Box contains: " << stringBox.getContents() << endl;
// 修改盒子里的内容
intBox.setContents(20);
cout << "After setting a new value, the Box contains: " << intBox.getContents() << endl;
system("pause");
return 0;
}
3.声明包含多个参数的模板
cpp
#include <iostream>
using namespace std;
// 声明一个有两个类型参数的模板类
template <typename T1, typename T2>
class Pair {
private:
T1 first; // 第一个元素的类型为T1
T2 second; // 第二个元素的类型为T2
public:
// 构造函数,初始化first和second
Pair(const T1& f, const T2& s) : first(f), second(s) {}
// 获取第一个元素的值
T1 getFirst() const { return first; }
// 获取第二个元素的值
T2 getSecond() const { return second; }
};
int main() {
// 创建一个整型和双精度浮点型的Pair对象
Pair<int, double> intDoublePair(10, 20.5);
// 使用cout输出Pair对象的两个元素的值
cout << "First: " << intDoublePair.getFirst() << ", Second: " << intDoublePair.getSecond() << endl;
system("pause");
return 0;
}
4.声明包含默认参数的模板
cpp
#include <iostream>
using namespace std;
// 声明一个模板类PairWithDefault,它有两个类型参数,
// 第二个参数T2有默认值int
template <typename T1, typename T2 = int>
class PairWithDefault {
private:
T1 first; // 第一个元素的类型为T1
T2 second; // 第二个元素的类型为T2,默认为int
public:
// 构造函数,使用两个参数分别初始化first和second
PairWithDefault(const T1& f, const T2& s = 0) : first(f), second(s) {}
// 获取第一个元素的值
T1 getFirst() const { return first; }
// 获取第二个元素的值
T2 getSecond() const { return second; }
};
int main() {
// 使用默认的第二个参数类型(即int)创建PairWithDefault对象
PairWithDefault<double> defaultPair(3.14);
cout << "First: " << defaultPair.getFirst() << ", Second: " << defaultPair.getSecond() << endl;
// 明确指定第二个参数类型为char,并创建PairWithDefault对象
PairWithDefault<double, char> explicitPair(2.71, 'A');
cout << "First: " << explicitPair.getFirst() << ", Second: " << static_cast<char>(explicitPair.getSecond()) << endl;
system("pause");
return 0;
}
5.参数量可变的模板
语法
cpp
template <typename... Types>
class MyClass {
// ...
};
例子
cpp
#include <iostream>
#include <string>
using namespace std;
// 变长模板函数print的声明
// 它可以接受任意数量和类型的参数
template <typename... Args>
void print(const Args&... args) {
(cout << ... << args) << endl; // 使用C++17的折叠表达式来连续输出所有参数,并在最后输出换行符
}
int main() {
// 调用print函数,传递多个不同类型的参数
print(1, 2, "Hello", 'a'); // 输出: 1 2 Hello a
system("pause");
return 0; // 程序正常结束,返回0
}
6.使用static_assert
执行编译阶段检查
static_assert
是C++11新增的功能,能够在不满足指定条件时禁止编译,它允许开发者在编译时对程序进行额外的约束和检查,从而提高代码的安全性和可维护性。
语法
cpp
static_assert(expression, "error message");
- expression:要检查的条件,必须是一个在编译时就能确定的布尔表达式
- "error message":如果条件不为真,编译器将显示这条错误信息
例子
cpp
#include <iostream>
template <int N>
void doSomethingElse() {
// 确保N大于0
static_assert(N > 0, "N must be positive");
// code
}
int main() {
doSomethingElse<1>(); // 通过编译,因为1是正数
// doSomethingElse<-1>(); // 不通过编译,因为-1不是正数
system("pause");
return 0;
}
PS:
- 务必使用模板来实现通用概念
- 非必要情况,请使用模板而不是宏
- 编写模板函数和模板类时,尽可能使用const