C++ 模版编程

最近在写一个C++调用Python的库,可以说把我所学到的关于模版的知识都用上了

真的是,用起来越简单的东西,做起来就越难

1.不定参数

为了方便,我想写一个能够传入任意数量和类型参数的函数,而且能够根据不同的类型进行映射

首先,为了解决映射,我们可以实现设置好映射,然后利用模版的特化,根据传入的类型的到正确的特化模版

然后在特化模版中存储着类型映射信息,例如,如果是int,就映射字符串i

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<typename T>
struct type_tratis {
std::string flag = "null";
};

template<>
struct type_tratis<int> {
std::string flag = "i";
};

int main() {
type_traits<int> s;
std::cout << s.flag << std::endl;
return 0;
}

然后,我要传入不定类型和数量的参数,可以使用不定参数模版

这个模版可以包含一个参数包,然后可以通过递归匹配层层展开

1
2
3
4
5
6
7
8
9
10
template<typename T>
void PythonLoader::ParseType(int count, T t) {
//包的最后一个
}

template<typename T, typename... Args>
void PythonLoader::ParseType(T t, Args... args) {
//解包
ParseType(args...);
}

这样,大抵完成了第一个目标

2.推断传入的tuple类型,然后赋予正确的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<class Tuple, std::size_t N>
struct TuplePrinter {
static void print(const Tuple& t)
{
TuplePrinter<Tuple, N - 1>::print(t);
std::cout << ", " << std::get<N - 1>(t);
}
};

template<class Tuple>
struct TuplePrinter<Tuple, 1>{
static void print(const Tuple& t)
{
std::cout << std::get<0>(t);
}
};

template<class... Args>
void PrintTuple(const std::tuple<Args...>& t)
{
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
}

使用这个方法是因为std::get<>只能接受`constant expression

于是就利用模版元编程达到遍历tuple中每一个变量的效果

对于每一个变量,我们可以这样获得它的原始类型

1
typedef typename std::tuple_element<N - 1, typename std::remove_reference<decltype(t)>::type>::type ValueType;

其实也就是利用

std::tuple_element<pos, [types]>::type

首先对于传入的一个tuple<int, int> i,如果直接放到[types]是行不通的,必须要获得类型数组[int,int]

所以直接获得dectyple(i)获得带引用的类型数组,然后用std::remove_reference<>::type获取原始类型数组,然后就能使用std::tuple_element<>::type获取某一个位置的原本类型了

可喜可贺可喜可贺

3.总结

虽然看起来也不是很难,但是充分说明了我的练习量还不够,在调试模版的时候花了很多时间

不过从中也慢慢摸清了模版的特性,模版的关键无它,唯类型推断与匹配