各类关键字

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当中传入参数.那么它就不是一个模糊的值.而是一个被定义的值.所以不能视为模板

小结

模板是一个模糊的概念,不是一个确定的概念.它只有在使用的时候才会被确定

posted @   俊king  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示