本文是学习 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;

};

完整代码如下

 // Study1.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <string>
#include <iostream> template <typename T>
void Register(T person)
{
Register(person, typename T::person_tag());
} struct student_tag {};
struct teacher_tag {}; template<typename T>
void Register(T p,student_tag) {
std::cout << __FUNCTION__ << " student_tag"<< std::endl;
} template<typename T>
void Register(T p, teacher_tag) {
std::cout << __FUNCTION__ << " teacher_tag"<<std::endl;
} void ModelInSTL() {
std::string person;
student_tag s;
teacher_tag t;
Register(person, s);
Register(person, t);
}
//=========================================================
typedef char(&yes_type)[]; // sizeof(yes_type)==1
typedef char(&no_type)[]; // sizeof(no_type)==2 template<class T>
struct does_sometypedef_exists
{
template<class U>
static yes_type check(U, typename U::key_type* = nullptr); // #1
static no_type check(...);
static T t; // 声明
static const bool value = sizeof(check(t)) == sizeof(yes_type);
}; struct A {};
struct B
{
typedef int key_type;
}; // key_type为成员函数
struct C { void key_type(void) {} }; // key_type为静态常量数据成员
struct D { static const bool key_type = false; }; struct E {
struct 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;
}; //========================================================= int main()
{
ModelInSTL();
std::cout << does_sometypedef_exists<A>::value << std::endl;
std::cout << does_sometypedef_exists<B>::value << std::endl;
std::cout << does_sometypedef_exists<C>::value << std::endl;
std::cout << does_sometypedef_exists<D>::value << std::endl;
std::cout << does_sometypedef_exists<E>::value << std::endl;
std::cout << std::endl;
std::cout << does_sometypedef_exists_1<A>::value << std::endl;
std::cout << does_sometypedef_exists_1<B>::value << std::endl;
std::cout << does_sometypedef_exists_1<C>::value << std::endl;
std::cout << does_sometypedef_exists_1<D>::value << std::endl;
std::cout << does_sometypedef_exists_1<E>::value << std::endl; return ;
}

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)
 摘自”boost/any.hpp”

 class any

 {

 public:

 class placeholder // 泛型数据容器holder的非泛型基类  

 {                   

 public:

 // 虚析构函数,为保证派生类对象能用基类指针析构

 virtual ~placeholder(){}

 public:

   // 提供关于类型的信息

 virtual const std::type_info & type() const = ;

 virtual placeholder * clone() const = ;  // 复制

 }; // placeholder

 template<typename ValueType>

 class holder : public placeholder

 {

 public:

 holder(const ValueType & value)

 : held(value)

 {}

 public:

 virtual const std::type_info & type() const

 {

   // typeid返回std::typeinfo对象引用,后者包含任意对象的类型信息, 如name,此外还提供operator==操作符你可以用typeid(oneObj)==typeid(anotherObj)来比两个对象之类型是否一致。

 return typeid(ValueType); 

 }

 virtual placeholder * clone() const

 {

 return new holder(held);  // 改写虚函数,返回自身的复制体

 }

 public:

 ValueType held; // 数据保存的地方

 }; // holder

 // 指向泛型数据容器holder的基类placeholder的指针

 placeholder * content;

 //模板构造函数,动态分配数据容器并调用其构造函数

 template<typename ValueType>

 any(const ValueType & value)

 : content(new holder<ValueType>(value))

 {}

 ...

 // 与模板构造函数一样,但使用了swap惯用手法

 template<typename ValueType>

 any & operator=(const ValueType & rhs)

 {

 // 先创建一个临时对象any(rhs),再调用下面的swap函数进行底层数据交换,注意与*this交换数据的是临时对象,所以rhs的底层数据并未被更改,只是在swap结束后临时对象拥有了*this的底层数据,而此时*this也拥有了临时对象构造时所拥有的rhs的数据的副本。然后临时对象由于生命期的结束而被自动析构,*this原来的底层数据随之烟消云散。

 any(rhs).swap(*this);

 return *this;

 }

 any & swap(any & rhs) //swap函数,交换底层数据

 {

 std::swap(content, rhs.content); // 只是简单地将两个指针的值互换

 return *this;

 }

 ~any()  //析构函数

 {

   //释放容器,用的是基类指针,这就是placeholder需要一个虚析构函数的原因

 delete content;

 }

 ...

 };

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

就是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; // 这儿有个向下类型转换

}

全部代码如下

 // UseRapidJsonSample.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream>
#include <string>
#include "JsonStringTool.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/document.h"
#include <boost/any.hpp>
#include <list>
#include <exception>
#include <memory>
//
//class AClass {};
//
//void BOOSTAnySample()
//{
// typedef std::list<boost::any> many;
// //any可存入任何类型
// many values;
// boost::any value = 1;
// values.push_back(value);
//
// value = "string";
// values.push_back(value);
//
// values.push_back(true);
// values.push_back(nullptr);
// values.push_back(AClass());
//}
//===========================================================
class any
{
public: class placeholder // 泛型数据容器holder的非泛型基类
{
public:
// 虚析构函数,为保证派生类对象能用基类指针析构
virtual ~placeholder() {} public:
// 提供关于类型的信息
virtual const std::type_info & type() const = ;
virtual placeholder * clone() const = ; // 复制
}; // placeholder template<typename ValueType>
class holder : public placeholder
{
public:
holder(const ValueType & value)
: held(value)
{}
public:
virtual const std::type_info & type() const
{
// typeid返回std::typeinfo对象引用,后者包含任意对象的类型信息, 如name,此外还提供operator==操作符你可以用typeid(oneObj)==typeid(anotherObj)来比两个对象之类型是否一致。
return typeid(ValueType);
} virtual placeholder * clone() const
{
return new holder(held); // 改写虚函数,返回自身的复制体
} public:
ValueType held; // 数据保存的地方
}; // holder // 指向泛型数据容器holder的基类placeholder的指针
placeholder * content; //模板构造函数,动态分配数据容器并调用其构造函数
template<typename ValueType>
any(const ValueType & value)
: content(new holder<ValueType>(value))
{} // 与模板构造函数一样,但使用了swap惯用手法
template<typename ValueType>
any & operator=(const ValueType & rhs)
{
// 先创建一个临时对象any(rhs),再调用下面的swap函数进行底层数据交换,注意与*this交换数据的是临时对象,所以rhs的底层数据并未被更改,只是在swap结束后临时对象拥有了*this的底层数据,而此时*this也拥有了临时对象构造时所拥有的rhs的数据的副本。然后临时对象由于生命期的结束而被自动析构,*this原来的底层数据随之烟消云散。
any(rhs).swap(*this);
return *this;
} any & swap(any & rhs) //swap函数,交换底层数据
{
std::swap(content, rhs.content); // 只是简单地将两个指针的值互换
return *this;
} ~any() //析构函数
{
//释放容器,用的是基类指针,这就是placeholder需要一个虚析构函数的原因
delete content;
} };
//
template<typename ValueType>
ValueType * any_cast(const any * operand)
{
// 这个类型检查很重要,后面会对它作更详细的解释
return
operand &&
(operand->content->type() == typeid(ValueType)) ? // #1
&((static_cast<any::holder<ValueType>*>(operand->content))->held)
: ; // 这儿有个向下类型转换
} template<typename ValueType>
ValueType any_cast(const any & operand)
{
//// 调用any_cast针对指针的版本。 const ValueType * result = any_cast<ValueType>(&operand); // 如果cast失败,即实际 保存的并非ValueType型数据,则抛出一个异常。
if (!result)
throw std::exception("bad alloc"); // 派生自std::bad_cast
return *result;
} int main()
{ any ai();
int i = any_cast<int>(ai);
std::cout << i << std::endl; any ad(3.12222222222222222);
double d = any_cast<double>(ad);
std::cout << d << std::endl; any ab(true);
bool b = any_cast<bool>(ab);
std::cout << b << std::endl; any ac('z');
char c = any_cast<char>(ac);
std::cout << c << std::endl; return ;
}

boost学习 内嵌类型检测 与 any 的代码练习的更多相关文章

  1. ARM GCC 内嵌(inline)汇编手册

    转自:http://blogold.chinaunix.net/u2/69404/showart_1922655.html ARM GCC 内嵌(inline)汇编手册 百度云:http://pan. ...

  2. ARM GCC 内嵌汇编手册

    转自:http://blogold.chinaunix.net/u2/69404/showart_1922655.html ARM GCC 内嵌(inline)汇编手册 关于这篇文档这篇文章是本人为方 ...

  3. [转]Traits 编程技法+模板偏特化+template参数推导+内嵌型别编程技巧

    STL中,traits编程技法得到了很大的应用,了解这个,才能一窥STL奥妙所在. 先将自己所理解的记录如下: Traits技术可以用来获得一个 类型 的相关信息的. 首先假如有以下一个泛型的迭代器类 ...

  4. LODOP内嵌挡住浏览器的div弹出层

    首先,做一个简单的div弹出层用于测试,该弹出层的介绍可查看本博客另一篇博文:[JS新手教程]浏览器弹出div层 然后加入LODOP内嵌,LODOP可以内嵌,C-LODOP不能内嵌,可以在IE等浏览器 ...

  5. Django之多对多表之through第三张表之InlineModelAdmin后台内嵌

    话不多说,来看表结构 这里有两个表,一个是阶段表,一个是老师表,一个老师可以带多个阶段,一个阶段也可以由多个老师带,所以是多对多关系 # 阶段表 class Stage(models.Model): ...

  6. Python3+Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)

    #!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)'''from ...

  7. 零基础入门学习Python(20)--函数:内嵌函数和闭包

    知识点 global关键字 使用global关键字,可以修改全局变量: >>> count = 5 >>> def Myfun(): count = 10 prin ...

  8. JS的静态类型检测,有内味儿了

    我们知道 TypeScript 2.3 以后的版本支持使用--checkJs对.js文件进行类型检查和错误提示. 但是由于 JavaScript 是弱类型语言,在编写代码的时候,是无法检测变量的类型的 ...

  9. Elastic search中使用nested类型的内嵌对象

    在大数据的应用环境中,往往使用反范式设计来提高读写性能. 假设我们有个类似简书的系统,系统里有文章,用户也可以对文章进行赞赏.在关系型数据库中,如果按照数据库范式设计,需要两张表:一张文章表和一张赞赏 ...

随机推荐

  1. 20165312 2017-2018-2 《JAVA程序设计》第6周学习总结

    20165312 2017-2018-2 <JAVA程序设计>第6周学习总结 一.在本周学习过程中遇到的问题以及对上周测试的查漏补缺 编写110页代码时出现问题,主类Test中创建CPU对 ...

  2. 快速傅立叶变换(FFT)算法

    已知多项式f(x)=a0+a1x+a2x2+...+am-1xm-1, g(x)=b0+b1x+b2x2+...+bn-1xn-1.利用卷积的蛮力算法,得到h(x)=f(x)g(x),这一过程的时间复 ...

  3. jquery如何实现当页面下拉到一定位置时,右下角出现回到顶部图标

    渐进式返回顶部

  4. k8s学习笔记之五:Pod资源清单spec字段常用字段及含义

    第一章.前言 在上一篇博客中,我们大致简述了一般情况下资源清单的格式,以及如何获得清单配置的命令帮助,下面我们再讲解下清单中spec字段中比较常见的字段及其含义 第二章.常用字段讲解 spec.con ...

  5. nodejs通过mocha处理运行文件路径下所有js文件

    1.获取文件路径: 方式一:整个js文件使用 var path=require('path');var public_path=path.resolve('../testcase/listData/* ...

  6. 3.Jmeter参数化

    1.参数化的三种方式 ${变量} 1 用户定义的变量 2 添加配置元件 CSV Data Set Config ,导入.csv文档 3 利用函数助手中的函数获取参数值     主要用 _Random函 ...

  7. 学习笔记 requests + BeautifulSoup

    第一步:requests get请求 # -*- coding:utf-8 -*- # 日期:2018/5/15 17:46 # Author:小鼠标 import requests url = &q ...

  8. hadoop的hdfs中的javaAPI操作

    package cn.itcast.bigdata.hdfs; import java.net.URI; import java.util.Iterator; import java.util.Map ...

  9. 分布式计算课程补充笔记 part 2

    ▶ 并行计算八字原则:负载均衡,通信极小 ▶ 并行计算基本形式:主从并行.流水线并行.工作池并行.功能分解.区域分解.递归分治 ▶ MPI 主要理念:进程 (process):无共享存储:显式消息传递 ...

  10. vue初体验

    作为一个前端的小菜鸟,在平时的开发与学习中,除了要深入了解javascript 及 css 的各种特性,熟悉一门框架也是必不可少的.vue以其小巧,轻便,学习平滑等各种特性深受欢迎. 这里总结一下小菜 ...