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类型的内嵌对象
在大数据的应用环境中,往往使用反范式设计来提高读写性能. 假设我们有个类似简书的系统,系统里有文章,用户也可以对文章进行赞赏.在关系型数据库中,如果按照数据库范式设计,需要两张表:一张文章表和一张赞赏 ...
随机推荐
- 物化视图SQL
物化视图SQL,如果没有结果集,就证明数据库中不存在物化视图 select a.owner,'' column_name,a.table_name,b.segment_name,b.segment_t ...
- linux查看用户登录,操作历史等
who 命令:显示当前当登录的用户的信息 who -b命令:显示系统最近一次的启动时间 w 命令:显示登录的用户及其当前执行的任务 last 命令:显示当前与过去登录系统的用户的信息 lastb 命令 ...
- select函数总结
阻塞方式block,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回.使用Select就可以完成非阻塞non-block,就是进程或线程执 ...
- 转:细说ASP.NET Windows身份认证
转自:https://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html 细说ASP.NET Windows身份认证 阅读目录 开始 认识A ...
- (转)cenntos 安装mongodb
转自 https://www.cnblogs.com/layezi/p/7290082.html 安装前注意: 此教程是通过yum安装的.仅限64位centos系统 安装步骤: 1.创建仓库文件: 1 ...
- mysql数据库优化(三)--分区
mysql的分区,分表 分区:把一个数据表的文件和索引分散存储在不同的物理文件中. 特点:业务层透明,无需任何修改,即使从新分表,也是在mysql层进行更改(业务层代码不动) 分表:把原来的表根据条件 ...
- VS2015密匙--VS2015打开丢失msvcp140.dll--cannot find one or more components ,please reinstall the application
win7旗舰版 64位 + vs2015 专业版 1.安装VS2015过程中可能需要用到的VS2015专业版钥匙:(测试,可用) HMGNV-WCYXV-X7G9W-YCX63-B98R2 2.VS2 ...
- ARCore中Pose类变换点的算法实现
ARCore中Pose类变换点的算法实现,主要分为两步,分别是平移和旋转. 1. 旋转向量:通过四元数计算旋转后的向量 参数列表:q表示四元数, v是长度为4的float数组,表示待旋转的向量, ...
- python基础数据篇
1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 ? 1 names = ['Alex',"Tenglan",' ...
- python tp_ready函数分析
int PyType_Ready(PyTypeObject *type) { PyObject *dict, *bases; PyTypeObject *base; Py_ssize_t i, n; ...