namespace
测试程序使用namespace
包裹
示例代码:
#include <iostream>
#include <memory>
#include <list>
namespace jj01
{
void test_member_template() {}
}
namespace jj02
{
template<typename T>
using Lst = list<T, allocator<T>>;
void test_template_template_param() {}
}
int main(int argc, char** argv)
{
jj01::test_member_template();
jj02::test_template_template_param();
}
类模板
可以允许使用者任意指定的部分可以抽出成为模板
template<typename T>
// 使用的时候在指明类型
class complex
{
public:
complex (T r = 0. T i = 0) : re(r), im(i) {}
complex& operator += (const complex&);
T real() const {return re;}
T imag() const {return im;}
private:
T re, im;s
}
函数模板
语法和类模板一样
template<typename T>
inline
const T& min(const T& a, const T& b) {return b < a ? b : a;}
// 使用的时候不需要指名类型 -> <符号的本质是操作符重载
stone r1(2, 3), r2(3, 3);
r3 = min(r1, r2);
成员模板
模板里面的member
,该member
本身又是一个template
-> 模板内的模板 -> 主要用来设计构造函数
示例代码:
template<class T1, class T2>
struct pair
{
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b) : first(a), second(b) {}
// 再设计模板
template<class U1, class U2>
pair(const pair<U1, U2>& p) : first(p.first), second(p.second) { }
};
模板特化
专门针对某一类型设计的函数
示例代码:
#pragma once
#ifndef __SPECIALIZATION__
#define __SPECIALIZATION__
template<class Key> // 要先有泛化.才有模板的特化
struct hash
{
};
template <>
struct hash<long>
{
size_t operator() (long x) const { return x; }
};
#endif // !__SPECIALIZATION__
partial specialization 模板偏特化(个数的偏特化,范围的偏特化)
个数偏特化:
template<typename T, typename Alloc=...>
class vector
{
}
T
是指定函数类型.Alloc
是指定函数的分配器(标准库的内容)
c++
当中最小单位是char
类型.八位,如果是bool
类型那么只占用一位.那么就不需要使用泛化
实际上就是在声明模板的时候指定一个模板的泛化值是什么(类似声明形参的时候赋予初始值)
示例代码:
template<typename Alloc=...>
class vertor<bool, Alloc>
{
}
范围上的偏特化
如果设计一个模板特化类型T
,但是他不是一个具体的类型.他是一个指针.指向任意类型.所以T
的范围就缩小了
示例代码:
template<typename T>
class C
{
}
在声明一个指针的T
template<typename U>
class C<U*>
{
}
如果使用者用的是指针,编译器会使用下面一套代码.如果是指针,那么编译器会用上面一套代码
T*
表示指向什么都可以
使用者声明方式:
c<string> obj1; // 使用上面一个T代码
c<string*> obj2; // 使用下面一个U*代码
template template parameter模板模板参数
声明一个模板.有两个参数.第二个参数也是一个模板
示例代码:
#pragma once
#ifndef __TEMPLATE__
#define __TEMPLATE__
template<typename T, template<typename T> class Container>
/* 在template尖括号的<>中间.typename和class是共通的 */
class XCls
{
public:
private:
Container<T> c; // 这个T是指前面的typename的T -> 这里写出的是list<string>
};
template<typename T>
using Lst = list<T, allocator<T>>
#endif // !__TEMPLATE__
目的是为了让使用者可以指定使用容器来构造类
容器需要指定元素类型和分配器
上面的模板模板声明完成后具体使用:
// 错误使用方式
// XCls<string, list> mylst1; -> list传入就是第二个Contrainer,会拿前面的T当前元素类型
// 之所以这里可以这样使用,是因为元素有第二模板参数.只是有默认值.如果这样使用语法过不了
// list的特性接收两个参数
XCls<string, Lst> mylst;
上诉代码当中传入的list
并没有绑定任何参数,所以它仍然是一个模糊的东西.这样才可以把它称之为模板
无法通过的原因是:容器接收好几个参数
如果只接收一个参数那么是可以通过的
示例代码:
#pragma
#ifndef __TEMPLATETWO__
#define __TEMPLATETWO__
template<typename T, template<typename T> class SmartPtr>
class XCls
{
public:
XCls() : sp(new T) { }
private:
SmartPtr<T> sp;
};
#endif // !__TEMPLATETWO__
使用方式:
XCls<string, shared_ptr> p1;
// XCls<double, unique_ptr> p2; -> 由于unique_ptr的特性所以上述的声明方式进行这样构造是不可以的
非模板模板偏特化:
template<class T, class Sequence = deque<T>>
class stack {
friend bool operator== <> (const stack&, const stack&);
friend bool operator< <> (const stack&, const stack&);
protected:
Sequence c; // 底层容器
};
在这段代码当中,由于Sequence
有默认初始值.所以在声明调用的时候有两种方式:
stack<int> s1;
stack<int, list<int>> s2;
在这个当中如果要修改第二个初始值.需要指定list<int>
并且向list
当中传入参数.那么它就不是一个模糊的值.而是一个被定义的值.所以不能视为模板
小结
模板是一个模糊的概念,不是一个确定的概念.它只有在使用的时候才会被确定
标签:__,const,代码,list,关键字,各类,template,模板 From: https://www.cnblogs.com/JunkingBoy/p/18133206