• 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
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    js用8421码实现10进制转2进制
    什么?toggle(fn1, fn2)函数在1.9版本jq被移除? 来来来,自己撸一个
    js获取鼠标点击的对象,点击另一个按钮删除该对象
    html5小结
    iphone状态栏高度?
    制作手机相册 全屏滚动插件fullpage.js
    js 相关知识整理(一)
    css 居中问题
    进度条
    @Html.Raw()
  • 原文地址:https://www.cnblogs.com/itdef/p/7783970.html
Copyright © 2020-2023  润新知