浅窥C++模板编程
Posted Coder学习路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅窥C++模板编程相关的知识,希望对你有一定的参考价值。
近期学习和编写代码时接触了一些关于C++模板编程的知识,深觉模板元编程是一个非常有趣的世界。因此写下本文,分享一些C++模板的一些知识点和应用,希望能对你有些帮助。
1. STL真香
Standard Template Library, STL
)。STL包含4个组件,分别为算法、容器、函数、迭代器,对于大多数C++程序员来说,容器应该是日常编码中最常使用的。
vector<int>
,这表示用
int
类型实例化模板
vector
。常用容器还有
deque
、
set
、
map
等,它们都属于模板类。此外,还有函数模板,如STL中提供的各种算法,它们都属于函数模板。
stack
、
queue
等最基础的数据结构或者
sort
、
merge
等算法时,都需要自行实现。而使用C++语言,这些都只是一行代码的问题。因此,当习惯了使用STL之后再转向C语言编程时,一定免不了感叹一句:STL真香,也让人感叹模板编程的魅力。
2. 如何在编译期计算阶乘
template <unsigned int n>
struct fact
{
enum
{
value = n * fact<n - 1>::value
};
};
template <>
struct fact<0>
{
enum
{
value = 1
};
};
int main()
{
cout << fact<5>().value << endl; // 输出 120 (5!)
return 0;
}
unsigned int
竟然也可以做函数形参!是的,整型的确可以作为模板形参,而这正是在编译期进行计算的关键。
value
,而
value = n * fact<n - 1>::value
。有点递归的感觉,也有点计算阶乘的感觉。既然像递归,那么递归结束条件是什么呢?
fact<0>
中,
value
的值为1,代表
0! = 1
。至此就完成了利用模板计算阶乘。需要注意的是,在上述代码中,阶乘的计算是在编译期完成的,在运行期, main 函数只需要输出 120 即可,并不会在运行期进行乘法运算。
3. 编译期确定数组长度
#include <iostream>
using namespace std;
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept
{
return N;
}
int main()
{
int a[] = {1, 23, 4, 5, 6};
const char name[] = "ad sdfs-s sd,sas";
cout << "arraySize = " << arraySize(a) << endl;
cout << "arraySize = " << arraySize(name) << endl;
char copy[arraySize(name)] = {'a', 'b', 'c'};
return 0;
}
std::size_t
,其中
std::size_t
为C++提供的一种类型别名,在我的机器中(64位),其就是64位的无符号整型:
typedef unsigned __int64 size_t;
。函数形参为
T (&)[N]
,即 T 类型长度为 N 的数组的引用。返回类型为
std::size_t
,同时声明了这个函数为
constexpr
,
constexpr
是 C++ 11 标准的一个关键字,代表一个常量表达式。函数体只有一条语句:
return N;
。
constexpr
共同完成了在编译器计算数组的长度,并以常量的形式返回。
sizeof
运算符,如
sizeof(a)/sizeof(int)
,这样即可计算名称为 a 的 int 类型数组的长度。
4. 打印任意类型的序列容器
int
、
char
、
double
等)的一系列重载函数;二为一个函数模板。代码如下:
// 重载基本类型,结合下面 template ,则可以打印任何元素为基本类型的容器
void print(char c)
{
cout << c;
}
void print(int i)
{
cout << i;
}
template <typename T>
void print(const T &container)
{
for (auto &elem : container)
print(elem);
cout << endl;
}
范围for循环
,递归调用 print 函数,即可实现打印任意类型容器。
5. 将任意内置类型转为二进制字符串
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
template <typename T>
string showBit(T n)
{
string res;
int bit_width = sizeof(n) * 8; // 二进制位数
for (int i = 0; i < bit_width; ++i, n >>= 1)
res.push_back((1 & n) ? '1' : '0');
reverse(res.begin(), res.end()); // 翻转
return res;
}
string showBit(float f)
{
int *pi = reinterpret_cast<int *>(&f); // 强制类型转换
return showBit<int>(*pi);
}
string showBit(double d)
{
long long *pl = reinterpret_cast<long long *>(&d);
return showBit<long long>(*pl);
}
string showBit(long double d)
{
long long *pl = reinterpret_cast<long long *>(&d);
return showBit<long long>(*pl);
}
int main()
{
cout << showBit(INT_MAX) << endl;
cout << showBit(INT_MIN) << endl;
cout << showBit(UINT32_MAX) << endl;
cout << showBit(-1) << endl;
cout << showBit('a') << endl;
cout << showBit(1.2f) << endl;
cout << showBit(1.2) << endl;
cout << showBit(static_cast<long double>(0.0)) << endl;
cout << showBit(0.0) << endl;
return 0;
}
>>
,而只有整型允许移位运算。特例化函数主要是为了处理浮点型数据,在函数内利用了一个小小的编程技巧:利用指针,将浮点型对应的二进制串不加改变的变为整型,然后再调用模板函数即可将浮点类型转换为二进制串。
以上是关于浅窥C++模板编程的主要内容,如果未能解决你的问题,请参考以下文章