本文是学习 boost源码的一些练习
参考文章来自
刘未鹏
C++的罗浮宫(http://blog.csdn.net/pongba)
目录
http://blog.csdn.net/pongba/article/category/37521
检测内嵌类型
检测一个类中是否存在指定的类型
那么只需要利用模板检测输入参数 根据参数的不同 导入到不同的函数中
类似
template <typename T> void Register(T person) { Register(person, typename T::person_tag()); }
struct student_tag {}; 16 struct teacher_tag {}; 17 18 template<typename T> 19 void Register(T p,student_tag) { 20 std::cout << __FUNCTION__ << " student_tag"<< std::endl; 21 } 22 23 template<typename T> 24 void Register(T p, teacher_tag) { 25 std::cout << __FUNCTION__ << " teacher_tag"<<std::endl; 26 }
那么只要输入的参数含有这个tag结构 就会输入到不同的函数中 这是stl经常使用的套路
另外一种需求是检测类中是否带有指定的type 而不是如上所述 要事先在类中定义好tag
比如我们要检测任意类型中是否有我们需要关注的key_type
定义如下
36 typedef char(&yes_type)[1]; // sizeof(yes_type)==1 37 typedef char(&no_type)[2]; // sizeof(no_type)==2 38 39 template<class T> 40 struct does_sometypedef_exists 41 { 42 template<class U> 43 static yes_type check(U, typename U::key_type* = nullptr); // #1 44 static no_type check(...); 45 static T t; // 声明 46 static const bool value = sizeof(check(t)) == sizeof(yes_type); 47 };
根据模板特性 如果输入的参数U 带有key_type 则check函数是该形式
static yes_type check(U, typename U::key_type* = nullptr);
返回 yes_type
输入参数U是其他类型 则check形式如下
static no_type check(...);
返回 no_type
根据定义 no_type yes_type长度不同
那么只需要检测check函数的返回长度 就可以确认输入的参数U是否带有key_type
static const bool value = sizeof(check(t)) == sizeof(yes_type);
我们查看下
does_sometypedef_exists<T>::type 是否为真就能确认T是否包含key_type
//================================================================================
同样的利用模板偏特化及默认模板参数的规则也可以实现
根据输入类型T是否包含key_type 适配不同版本代码
template<class T,class>
struct check_helper
{
typedef T type;
};
template<class T,class =T>
struct does_sometypedef_exists_1
{
static const bool value=false;
};
template<class T>
struct does_sometypedef_exists_1<T,
typename check_helper<T, typename T::key_type>::type>
{
static const bool value=true;
};
完整代码如下
1 // Study1.cpp: 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <string> 6 #include <iostream> 7 8 9 template <typename T> 10 void Register(T person) 11 { 12 Register(person, typename T::person_tag()); 13 } 14 15 struct student_tag {}; 16 struct teacher_tag {}; 17 18 template<typename T> 19 void Register(T p,student_tag) { 20 std::cout << __FUNCTION__ << " student_tag"<< std::endl; 21 } 22 23 template<typename T> 24 void Register(T p, teacher_tag) { 25 std::cout << __FUNCTION__ << " teacher_tag"<<std::endl; 26 } 27 28 void ModelInSTL() { 29 std::string person; 30 student_tag s; 31 teacher_tag t; 32 Register(person, s); 33 Register(person, t); 34 } 35 //========================================================= 36 typedef char(&yes_type)[1]; // sizeof(yes_type)==1 37 typedef char(&no_type)[2]; // sizeof(no_type)==2 38 39 template<class T> 40 struct does_sometypedef_exists 41 { 42 template<class U> 43 static yes_type check(U, typename U::key_type* = nullptr); // #1 44 static no_type check(...); 45 static T t; // 声明 46 static const bool value = sizeof(check(t)) == sizeof(yes_type); 47 }; 48 49 struct A {}; 50 struct B 51 { 52 typedef int key_type; 53 }; 54 55 // key_type为成员函数 56 struct C { void key_type(void) {} }; 57 58 // key_type为静态常量数据成员 59 struct D { static const bool key_type = false; }; 60 61 struct E { 62 struct key_type 63 {}; 64 }; 65 66 //============================================================== 67 68 template<class T, class> 69 struct check_helper 70 { 71 typedef T type; 72 }; 73 74 template<class T, class = T> 75 struct does_sometypedef_exists_1 76 { 77 static const bool value = false; 78 }; 79 80 template<class T> 81 struct does_sometypedef_exists_1<T, 82 typename check_helper<T, typename T::key_type>::type> 83 { 84 static const bool value = true; 85 }; 86 87 //========================================================= 88 89 90 int main() 91 { 92 ModelInSTL(); 93 std::cout << does_sometypedef_exists<A>::value << std::endl; 94 std::cout << does_sometypedef_exists<B>::value << std::endl; 95 std::cout << does_sometypedef_exists<C>::value << std::endl; 96 std::cout << does_sometypedef_exists<D>::value << std::endl; 97 std::cout << does_sometypedef_exists<E>::value << std::endl; 98 std::cout << std::endl; 99 std::cout << does_sometypedef_exists_1<A>::value << std::endl; 100 std::cout << does_sometypedef_exists_1<B>::value << std::endl; 101 std::cout << does_sometypedef_exists_1<C>::value << std::endl; 102 std::cout << does_sometypedef_exists_1<D>::value << std::endl; 103 std::cout << does_sometypedef_exists_1<E>::value << std::endl; 104 105 return 0; 106 }
ANY
BOOST中有一个ANY类
可以接受任意类型的输入
示例如下
11 #include <boost/any.hpp> 12 #include <list> 13 #include <exception> 14 #include <memory> 15 // 16 //class AClass {}; 17 // 18 //void BOOSTAnySample() 19 //{ 20 // typedef std::list<boost::any> many; 21 // //any可存入任何类型 22 // many values; 23 // boost::any value = 1; 24 // values.push_back(value); 25 // 26 // value = "string"; 27 // values.push_back(value); 28 // 29 // values.push_back(true); 30 // values.push_back(nullptr); 31 // values.push_back(AClass()); 32 //}
根据使用方式 any不能定义模板 因为我们不可能使用any<int> a = 1; 那同定义 int a = 1就没区别了
所以any类中肯定有一个与输入类型相同的元素进行存储 但是any本身没有模板 那么这个存储输入类型的元素肯定是指针 但是指针也无法指定存储的类型
那么解决办法是? 就是指针是一个基类指针 同时指向一个带模板的继承基类的类
那么基本上代码就类似以下(代码来自刘未鹏的博客 http://blog.csdn.net/pongba/article/details/82811)
1 摘自”boost/any.hpp” 2 3 4 5 class any 6 7 { 8 9 public: 10 11 12 13 class placeholder // 泛型数据容器holder的非泛型基类 14 15 { 16 17 public: 18 19 // 虚析构函数,为保证派生类对象能用基类指针析构 20 21 virtual ~placeholder(){} 22 23 24 25 public: 26 27 // 提供关于类型的信息 28 29 virtual const std::type_info & type() const = 0; 30 31 virtual placeholder * clone() const = 0; // 复制 32 33 }; // placeholder 34 35 36 37 template<typename ValueType> 38 39 class holder : public placeholder 40 41 { 42 43 public: 44 45 holder(const ValueType & value) 46 47 : held(value) 48 49 {} 50 51 public: 52 53 virtual const std::type_info & type() const 54 55 { 56 57 // typeid返回std::typeinfo对象引用,后者包含任意对象的类型信息, 如name,此外还提供operator==操作符你可以用typeid(oneObj)==typeid(anotherObj)来比两个对象之类型是否一致。 58 59 return typeid(ValueType); 60 61 } 62 63 64 65 virtual placeholder * clone() const 66 67 { 68 69 return new holder(held); // 改写虚函数,返回自身的复制体 70 71 } 72 73 74 75 public: 76 77 ValueType held; // 数据保存的地方 78 79 }; // holder 80 81 82 83 // 指向泛型数据容器holder的基类placeholder的指针 84 85 placeholder * content; 86 87 88 89 //模板构造函数,动态分配数据容器并调用其构造函数 90 91 template<typename ValueType> 92 93 any(const ValueType & value) 94 95 : content(new holder<ValueType>(value)) 96 97 {} 98 99 ... 100 101 // 与模板构造函数一样,但使用了swap惯用手法 102 103 template<typename ValueType> 104 105 any & operator=(const ValueType & rhs) 106 107 { 108 109 // 先创建一个临时对象any(rhs),再调用下面的swap函数进行底层数据交换,注意与*this交换数据的是临时对象,所以rhs的底层数据并未被更改,只是在swap结束后临时对象拥有了*this的底层数据,而此时*this也拥有了临时对象构造时所拥有的rhs的数据的副本。然后临时对象由于生命期的结束而被自动析构,*this原来的底层数据随之烟消云散。 110 111 any(rhs).swap(*this); 112 113 return *this; 114 115 } 116 117 118 119 any & swap(any & rhs) //swap函数,交换底层数据 120 121 { 122 123 std::swap(content, rhs.content); // 只是简单地将两个指针的值互换 124 125 return *this; 126 127 } 128 129 130 131 ~any() //析构函数 132 133 { 134 135 //释放容器,用的是基类指针,这就是placeholder需要一个虚析构函数的原因 136 137 delete content; 138 139 } 140 141 ... 142 143 };
存储之后 在赋值给其他元素的过程中 我们需要一个转换过程
就是any_cast<typename T>()
代码如下
(代码来自刘未鹏的博客 http://blog.csdn.net/pongba/article/details/82811)
template<typename ValueType>
ValueType any_cast(const any & operand)
{
// 调用any_cast针对指针的版本。
const ValueType * result = any_cast<ValueType>(&operand);
// 如果cast失败,即实际 保存的并非ValueType型数据,则抛出一个异常。
if(!result)
throw bad_any_cast(); // 派生自std::bad_cast
return *result;
}
template<typename ValueType>
ValueType * any_cast(any * operand)
{
// 这个类型检查很重要,后面会对它作更详细的解释
return
operand &&
(operand->type()==typeid(ValueType)) ? // #1
&static_cast<any::holder<ValueType>*>(operand->content)->held
: 0; // 这儿有个向下类型转换
}
全部代码如下
1 // UseRapidJsonSample.cpp: 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include <string> 7 #include "JsonStringTool.h" 8 #include "rapidjson/writer.h" 9 #include "rapidjson/stringbuffer.h" 10 #include "rapidjson/document.h" 11 #include <boost/any.hpp> 12 #include <list> 13 #include <exception> 14 #include <memory> 15 // 16 //class AClass {}; 17 // 18 //void BOOSTAnySample() 19 //{ 20 // typedef std::list<boost::any> many; 21 // //any可存入任何类型 22 // many values; 23 // boost::any value = 1; 24 // values.push_back(value); 25 // 26 // value = "string"; 27 // values.push_back(value); 28 // 29 // values.push_back(true); 30 // values.push_back(nullptr); 31 // values.push_back(AClass()); 32 //} 33 //=========================================================== 34 class any 35 { 36 public: 37 38 class placeholder // 泛型数据容器holder的非泛型基类 39 { 40 public: 41 // 虚析构函数,为保证派生类对象能用基类指针析构 42 virtual ~placeholder() {} 43 44 public: 45 // 提供关于类型的信息 46 virtual const std::type_info & type() const = 0; 47 virtual placeholder * clone() const = 0; // 复制 48 }; // placeholder 49 50 template<typename ValueType> 51 class holder : public placeholder 52 { 53 public: 54 holder(const ValueType & value) 55 : held(value) 56 {} 57 public: 58 virtual const std::type_info & type() const 59 { 60 // typeid返回std::typeinfo对象引用,后者包含任意对象的类型信息, 如name,此外还提供operator==操作符你可以用typeid(oneObj)==typeid(anotherObj)来比两个对象之类型是否一致。 61 return typeid(ValueType); 62 } 63 64 virtual placeholder * clone() const 65 { 66 return new holder(held); // 改写虚函数,返回自身的复制体 67 } 68 69 public: 70 ValueType held; // 数据保存的地方 71 }; // holder 72 73 // 指向泛型数据容器holder的基类placeholder的指针 74 placeholder * content; 75 76 //模板构造函数,动态分配数据容器并调用其构造函数 77 template<typename ValueType> 78 any(const ValueType & value) 79 : content(new holder<ValueType>(value)) 80 {} 81 82 // 与模板构造函数一样,但使用了swap惯用手法 83 template<typename ValueType> 84 any & operator=(const ValueType & rhs) 85 { 86 // 先创建一个临时对象any(rhs),再调用下面的swap函数进行底层数据交换,注意与*this交换数据的是临时对象,所以rhs的底层数据并未被更改,只是在swap结束后临时对象拥有了*this的底层数据,而此时*this也拥有了临时对象构造时所拥有的rhs的数据的副本。然后临时对象由于生命期的结束而被自动析构,*this原来的底层数据随之烟消云散。 87 any(rhs).swap(*this); 88 return *this; 89 } 90 91 any & swap(any & rhs) //swap函数,交换底层数据 92 { 93 std::swap(content, rhs.content); // 只是简单地将两个指针的值互换 94 return *this; 95 } 96 97 ~any() //析构函数 98 { 99 //释放容器,用的是基类指针,这就是placeholder需要一个虚析构函数的原因 100 delete content; 101 } 102 103 }; 104 // 105 template<typename ValueType> 106 ValueType * any_cast(const any * operand) 107 { 108 // 这个类型检查很重要,后面会对它作更详细的解释 109 return 110 operand && 111 (operand->content->type() == typeid(ValueType)) ? // #1 112 &((static_cast<any::holder<ValueType>*>(operand->content))->held) 113 : 0; // 这儿有个向下类型转换 114 } 115 116 117 template<typename ValueType> 118 ValueType any_cast(const any & operand) 119 { 120 //// 调用any_cast针对指针的版本。 121 122 const ValueType * result = any_cast<ValueType>(&operand); 123 124 // 如果cast失败,即实际 保存的并非ValueType型数据,则抛出一个异常。 125 if (!result) 126 throw std::exception("bad alloc"); // 派生自std::bad_cast 127 return *result; 128 } 129 130 131 int main() 132 { 133 134 any ai(1); 135 int i = any_cast<int>(ai); 136 std::cout << i << std::endl; 137 138 any ad(3.12222222222222222); 139 double d = any_cast<double>(ad); 140 std::cout << d << std::endl; 141 142 any ab(true); 143 bool b = any_cast<bool>(ab); 144 std::cout << b << std::endl; 145 146 any ac('z'); 147 char c = any_cast<char>(ac); 148 std::cout << c << std::endl; 149 150 return 0; 151 }