【C++】编写通用模板代码的重要技巧:T()
const T& val = T()
以下是vector类模拟实现中 resize() 部分代码:
/* resize */
// val不能给0,因为不知道T的类型,所以给一个T的缺省值
void resize(size_t n, const T& val = T())
{// 缩小sizeif (n < size())_finish = _start + n;else // 增大size{// 假如需要扩容if (n > capacity()){reserve(n);}while (_finish < _start + n){*_finish = val;++_finish;}}
}
const T& val = T()
的含义
这行代码实际上包含了三个关键概念:
1. T()
- 值初始化
T()
表示创建一个类型为T
的临时对象,并使用值初始化对于内置类型(如
int
,double
,指针
等),T()
会将其初始化为零值:int()
→0
double()
→0.0
char()
→'\0'
指针()
→nullptr
对于类类型,
T()
会调用默认构造函数
2. const T&
- 常量引用
使用常量引用可以避免不必要的对象拷贝
常量引用可以绑定到临时对象(如
T()
创建的对象)
3. = T()
- 默认参数
这是函数的默认参数,如果调用时不提供这个参数,就使用
T()
作为默认值
为什么要这样设计?
通用性
由于 vector
是模板类,需要处理任意类型 T
:
如果是
vector<int>
,T()
就是0
如果是
vector<string>
,T()
就是空字符串如果是
vector<MyClass>
,T()
会调用MyClass
的默认构造函数
示例代码:
vector<int> v1;
v1.resize(10); // 使用默认值 int() = 0,所有新元素初始化为0vector<double> v2;
v2.resize(5); // 使用默认值 double() = 0.0vector<string> v3;
v3.resize(3); // 使用默认值 string() = 空字符串// 也可以显式指定值
v1.resize(15, 100); // 新元素初始化为100
v3.resize(5, "hello");// 新元素初始化为"hello"
为什么不能直接用 0
?
为什么不能写成 void resize(size_t n, const T& val = 0)
?
这是因为:
类型不匹配:如果
T
是string
,0
不是有效的字符串值缺乏通用性:不是所有类型都能从
0
构造编译错误:对于不能从
0
转换的类型,代码无法编译
而 T()
为每种类型提供了最合适的"零值"或默认值,保证了代码的通用性和类型安全。
总结
const T& val = T()
是一个巧妙的设计:
通用:适用于任何类型
T
高效:使用引用避免拷贝
安全:提供类型安全的默认值
灵活:允许调用者提供自定义值,也有合理的默认值
这种写法在STL和现代C++库中非常常见,是编写通用模板代码的重要技巧之一。