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;
};
完整代码如下
// 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 的代码练习的更多相关文章
- ARM GCC 内嵌(inline)汇编手册
转自:http://blogold.chinaunix.net/u2/69404/showart_1922655.html ARM GCC 内嵌(inline)汇编手册 百度云:http://pan. ...
- ARM GCC 内嵌汇编手册
转自:http://blogold.chinaunix.net/u2/69404/showart_1922655.html ARM GCC 内嵌(inline)汇编手册 关于这篇文档这篇文章是本人为方 ...
- [转]Traits 编程技法+模板偏特化+template参数推导+内嵌型别编程技巧
STL中,traits编程技法得到了很大的应用,了解这个,才能一窥STL奥妙所在. 先将自己所理解的记录如下: Traits技术可以用来获得一个 类型 的相关信息的. 首先假如有以下一个泛型的迭代器类 ...
- LODOP内嵌挡住浏览器的div弹出层
首先,做一个简单的div弹出层用于测试,该弹出层的介绍可查看本博客另一篇博文:[JS新手教程]浏览器弹出div层 然后加入LODOP内嵌,LODOP可以内嵌,C-LODOP不能内嵌,可以在IE等浏览器 ...
- Django之多对多表之through第三张表之InlineModelAdmin后台内嵌
话不多说,来看表结构 这里有两个表,一个是阶段表,一个是老师表,一个老师可以带多个阶段,一个阶段也可以由多个老师带,所以是多对多关系 # 阶段表 class Stage(models.Model): ...
- Python3+Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)'''from ...
- 零基础入门学习Python(20)--函数:内嵌函数和闭包
知识点 global关键字 使用global关键字,可以修改全局变量: >>> count = 5 >>> def Myfun(): count = 10 prin ...
- JS的静态类型检测,有内味儿了
我们知道 TypeScript 2.3 以后的版本支持使用--checkJs对.js文件进行类型检查和错误提示. 但是由于 JavaScript 是弱类型语言,在编写代码的时候,是无法检测变量的类型的 ...
- Elastic search中使用nested类型的内嵌对象
在大数据的应用环境中,往往使用反范式设计来提高读写性能. 假设我们有个类似简书的系统,系统里有文章,用户也可以对文章进行赞赏.在关系型数据库中,如果按照数据库范式设计,需要两张表:一张文章表和一张赞赏 ...
随机推荐
- 后台自动运行,定期记录定位数据(Hbuilder监听 app由前台切换到后台、切换运行环境的 监听方法)
http://ask.dcloud.net.cn/question/28090 https://blog.csdn.net/qq_37508970/article/details/86649703 各 ...
- [蓝桥杯]PREV-7.历届试题_连号区间数
问题描述 小明这些天一直在思考这样一个奇怪而有趣的问题: 在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是: 如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增 ...
- TCP/IP学习20180630-数据链路层-router choose
IP路由选择 当一个IP数据包准备好了的时候,IP数据包(或者说是路由器)是如何将数据包送到目的地的呢?它是怎么选择一个合适的路径来"送货"的呢? 最特殊的情况是目的主机和主机直连 ...
- Scrapy学习篇(十三)之scrapy+selenum获取网站cookie并保存带本地
参考:https://www.cnblogs.com/small-bud/p/9064674.html 和selenium登录51job的例子
- SYSAUX表空间清理
最近zabbix告警某业务sysaux表空间使用率超过95%,使用sql查看sysaux表空间设置了32G,32G的表空间竟然使用了95%.一般来讲除开业务数据存放的表空间,DBA要着重关注SYSTE ...
- 刘志梅 201771010115 《面向对象程序设计(java)》 第七周学习总结
实验七 继承附加实验 实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: 即将类中的域标记为private,而方法标记为public.任何声明为priv ...
- python网页爬虫开发之二
1.网站robots robotparser模块首先加载robots.txt文件,然后通过can_fetch()函数确定指定的用户代理是否允许访问网页. 2.识别网站技术 3.下载网页 使用urlli ...
- 实验五:Xen环境下多虚拟机的桥接配置
实验名称: Xen环境下多虚拟机的桥接配置 实验环境: 这里我们首先需要有一台已经安装好的虚拟机机,能够正常运行,且网卡正常,如下图: 实验需求: 进行虚拟机的复制,并添加新的网桥配置,然后将两台虚拟 ...
- kubernetes学习笔记之十:RBAC
第一章.RBAC介绍 在Kubernetes中,授权有ABAC(基于属性的访问控制).RBAC(基于角色的访问控制).Webhook.Node.AlwaysDeny(一直拒绝)和AlwaysAllow ...
- Vue 封装的noData组件
<template> <div :style="{color: fontColor}" :class="['noDataView', iconType] ...