C++语言导学(8): 模板¶
引言¶
模板是一个很复杂的主题,这里只涉及最基础的部分。
模板(template)是一个类或一个函数,可以用一组类型或值来进行参数化。
模板是一种编译时机制,一个模板加上一组模板实参被称为特例化
,会由编译器根据实参自动生成对应的代码进而编译。
模板参数:类型¶
比如:
tempalte<typename T>
class Vector{
private:
T* elem;
int sz;
public:
explicit Vector(int s);
~Vector(){ delete[] elem;}
//...
T& operator[](int i);
const T& operator[](int i) const;
int size(){ return sz; }
};
template<typename T>
Vector<T>::Vector(int s){
if(s < 0)
throw Negative_size();
elem = new T[s];
sz = s;
}
//...
这里的typename T
就是指的模板类型参数T。
可以给自定义类型定义begin()和end()函数以支持范围for循环:
template<typename T>
T* begin(Vector<T>& x)
{
return x.size() ? &x[0] : nullptr;
}
template<typename T>
T* end(Vector<T>& x)
{
retur x.size() ? &x[0]+x.size() : nullptr;
}
void f(Vector<string>& s)
{
for(auto &x: s)
{
cout << s << endl;
}
}
另外,一旦使用模板,则声明和实现要放在一起,不能分开放到头文件和实现文件中,不支持分离编译。
模板参数:值¶
template<typenaem T, int N>
struct Buffer{
using value_type = T;
constexpr int size(){ return N; }
//...
};
Buffer<int, 10> buf;
Buffer<char, 1024> buf;
Buffer<int, 10>::value_type x; // 等同: int x
Buffer<char, 1024>::value_type ch; // 等同: char ch;
这里的int N
则是模板值参数,模板值参数必须是常量表达式。
这里用到using
是模板的别名功能,用于简化符号,写出更通用、抽象的模板,建议为自己的模板定义value_type
。
参数化:函数模板¶
template<typename Sequence, typename Value>
Value sum(const Sequence&s, Value v)
{
for(auto x: s)
{
v += x;
}
return v;
}
vector<int> vi{1,2,3,4,5};
int x = sum(vi, 0); // 15
函数模板可以作用于类的成员函数,但不能是virutal
成员函数,因为virutal
是运行时概念,而模板是编译时概念。
参数化:函数对象¶
模板用于函数对象(Function Object, functor):
template<typename T>
class Less_than{
const T val;
public:
Less_than(const T& v): val(v){}
bool operator(){cosnt T&x) const { return x < val; }
};
Less_than lti{42};
Less_than lts1{"Hello"s}; // 模板自动推断是string
Less_than<string> lts2{"Hello"}; // 不明确指定string则会推断为const char *
函数对象非常适合作为算法的参数。
参数化:lambda表达式¶
带有auto
参数的lambda成为了一个模板,又称泛型lambda
:
template<typename S>
void rotate_add_draw(vector<S>& v, int r)
{
for_all(v, [](auto& s){ s->rotate(r); s->draw(r);});
}
vector<unique_ptr<Shape>> v1;
vector<Shape*> v2;
rotate_and_draw(v1, 45);
rotate_and_draw(v2, 90);
通过auto
来自动推断,从而达到模板参数化的效果。
总结¶
- 使用模块以提高代码的抽象水平
- 如果只需要简单的函数对象,则首选lambda表达式代替
- 不能将虚函数成员使用模板来定义
- 利用模板别名简化符号以隐藏实现细节
- 模板不可以分离编译,不能头文件和实现文件分开定义。
- 微信搜索: 「 MinYiLife 」, 关注公众号!
- 本文链接: https://www.lesliezhu.com/blog/2022/11/01/cpp_8/
- 版权声明: 原创文章,如需转载请注明文章作者和出处。谢谢!