|
在C++11后的C++中,标准库为我们提供了不少的工具。

这5个工具都是利用模板完成,接下来我会写出这几个工具的简易实现。
本期先来看看tuple的实现。
头文件<tuple>
创建一个tuple
tuple<int, char, string>t(114, &#39;&&#39;, &#34;hello world&#34;);
获取tuple中的值
cout << get<0>(t) << endl;
cout << get<1>(t) << endl;
cout << get<2>(t) << endl;
注意,这里 <> 内放得是常量。例如 pair的first ,second 。 这里的get<0/1/2> 可以理解为
tuple.No1 ; tuple.No2 ; tuple.No3 这样的。
来看一下如何实现
首先是定义
template<typename ...Ty>struct Tuple;
这里,我们用到了,模板的不定长参数 ( 使用C++11变长参数模板 处理任意长度、类型之参数实例
简单的理解就是 ...Ty 表示把一堆类型给打包

我们通过Ty... 就可以将其解包

template<>struct Tuple<> {};
template<typename Ty1, typename ...Ty2>
struct Tuple<Ty1, Ty2...> : Tuple<Ty2...> {
Ty1 val;
};
这样当我们定义这样类型时
Tuple<int, char, string>
最终会产生这些类型
template<>
struct Tuple<>
{
};
template<>
struct Tuple<std::basic_string<char> > : public Tuple<>
{
std::basic_string<char> val;
};
template<>
struct Tuple<char, std::basic_string<char> > : public Tuple<std::basic_string<char> >
{
char val;
};
template<>
struct Tuple<int, char, std::basic_string<char> > : public Tuple<char, std::basic_string<char> >
{
int val;
};
根据这个继承关系,我们可以写出其内存结构

添加构造函数
template<typename Ty1, typename ...Ty2>
struct Tuple<Ty1, Ty2...> : Tuple<Ty2...> {
Ty1 val;
using Base = Tuple<Ty2...>;
Tuple() {}
Tuple(Ty1 v, Ty2... args) : val(v), Base(args...) {}
};
此时就能使用这样的创建了
Tuple<int, int, string> t(114, 514, &#34;1919810&#34;);
问题是如何访问数据呢?
我们可以加上这样的一个函数
Base& getBase() {
return *this;
}
可以这样访问数据
cout << t.val << endl;
cout << t.getBase().val << endl;
cout << t.getBase().getBase().val << endl;
就是通过一个类型转换,让编译器把<int,char,string>的一块内存,看成<char,string>

不过这样的访问着实有点不优雅,我们希望可以实现一个get
其实做法和上面的类似,例如<int,int,char,string> 当我想要get<2> 的时候,就去找到<char,string>的类型,然后类型转换一下。
对此,你可能需要一点点模板元编程的知识。
严格鸽:现代C++学习 模板元编程入门
template<int idx, typename _Tuple>
struct Tuple_element {
using Type = typename Tuple_element<idx - 1, typename _Tuple::Base>::Type;
};
template<typename _Tuple >
struct Tuple_element<0, _Tuple> {
using Type = _Tuple;
};
使用效果

这样就可以写出自己的get了
template<int idx, typename _Tuple>
constexpr auto& Get(_Tuple& t) {
using Type = typename Tuple_element < idx, _Tuple>::Type;
return static_cast<Type&>(t).val;
}
使用
Tuple<int, int, char, string>x(114, 514, &#39;a&#39;, &#34;soul&#34;);
Get<0>(x) = 1919;
Get<1>(x) = 810;
cout << Get<0>(x) << Get<1>(x) << endl;
cout << Get<2>(x) << Get<3>(x) << endl;
最后我们来实现一个判断是否相等。
首先,比较两个元组,两个元组的参数数量应该是一样的
template<typename ...Ty1, typename ...Ty2>
bool operator == (const Tuple<Ty1...>& L, const Tuple<Ty2...>& R) {
if (sizeof...(Ty1) != sizeof...(Ty2))return false;
这里的sizeof 就是 计算不定长参数的个数。不过这里其实,如果参数数量对不上,根本就过不了下面的编译。
所以直接这样
template<typename ...Ty1, typename ...Ty2>
bool operator == (const Tuple<Ty1...>& L, const Tuple<Ty2...>& R) {
return L.equal(R);
}
并添加这个函数
template <class... Ty>
bool equal(const Tuple<Ty...>& rhs)const {
return this->val == rhs.val && Base::equal(rhs.getBase());
}
做法就是不断的递归,当然,一开始的空基类也要写个函数
template <class... Ty>
bool equal(const Tuple<>& rhs)const {
return true;
}
这样判断就完成了
Tuple<int, int, char, string>x(114, 514, &#39;a&#39;, &#34;soul&#34;);
Tuple<int, int, char, string>y(114, 514, &#39;a&#39;, &#34;soul&#34;);
cout << (x == y) << endl;
Get<3>(y) = &#39;4&#39;;
cout << (x == y) << endl;
这样一个简易的tuple就完成了,放上完整代码,与一些测试例。
template<typename ...Ty>struct Tuple;
template<>struct Tuple<> {
template <class... Ty>
bool equal(const Tuple<>& rhs)const {
return true;
}
};
template<typename Ty1, typename ...Ty2>
struct Tuple<Ty1, Ty2...> : Tuple<Ty2...> {
Ty1 val;
using Base = Tuple<Ty2...>;
Tuple() {}
Tuple(Ty1 v, Ty2... args) : val(v), Base(args...) {}
Base& getBase() {
return *this;
}
const Base& getBase() const {
return *this;
}
template <class... Ty>
bool equal(const Tuple<Ty...>& rhs)const {
return this->val == rhs.val && Base::equal(rhs.getBase());
}
};
template<int idx, typename _Tuple>
struct Tuple_element {
using Type = typename Tuple_element<idx - 1, typename _Tuple::Base>::Type;
};
template<typename _Tuple >
struct Tuple_element<0, _Tuple> {
using Type = _Tuple;
};
template<int idx, typename _Tuple>
constexpr auto& Get(_Tuple& t) {
using Type = typename Tuple_element < idx, _Tuple>::Type;
return static_cast<Type&>(t).val;
}
template<typename ...Ty1, typename ...Ty2>
bool operator == (const Tuple<Ty1...>& L, const Tuple<Ty2...>& R) {
return L.equal(R);
}
int main()
{
Tuple<int, string> t(21, &#34;ygg&#34;);
vector<Tuple<int, int, double>>vec;
for (int i = 1; i <= 10; i++) {
vec.push_back({ i, i, 1.0 / i });
}
for (auto& x : vec) {
cout << Get<0>(x) << &#34; &#34; << Get<1>(x) << &#34; &#34; << Get<2>(x) << endl;
}
}
一些细节,比较拷贝构造,移动构造什么的,大家自己完善吧。 |
|