boost学习 内嵌类型检测 与 any 的代码练习

本文是学习 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 }
View Code


 

 

 

 

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 };
View Code

 

存储之后 在赋值给其他元素的过程中 我们需要一个转换过程

就是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 }
View Code

 

posted on 2017-11-04 17:37  itdef  阅读(442)  评论(0编辑  收藏  举报

导航