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类型的内嵌对象
在大数据的应用环境中,往往使用反范式设计来提高读写性能. 假设我们有个类似简书的系统,系统里有文章,用户也可以对文章进行赞赏.在关系型数据库中,如果按照数据库范式设计,需要两张表:一张文章表和一张赞赏 ...
随机推荐
- 20165312 2017-2018-2 《JAVA程序设计》第6周学习总结
20165312 2017-2018-2 <JAVA程序设计>第6周学习总结 一.在本周学习过程中遇到的问题以及对上周测试的查漏补缺 编写110页代码时出现问题,主类Test中创建CPU对 ...
- 快速傅立叶变换(FFT)算法
已知多项式f(x)=a0+a1x+a2x2+...+am-1xm-1, g(x)=b0+b1x+b2x2+...+bn-1xn-1.利用卷积的蛮力算法,得到h(x)=f(x)g(x),这一过程的时间复 ...
- jquery如何实现当页面下拉到一定位置时,右下角出现回到顶部图标
渐进式返回顶部
- k8s学习笔记之五:Pod资源清单spec字段常用字段及含义
第一章.前言 在上一篇博客中,我们大致简述了一般情况下资源清单的格式,以及如何获得清单配置的命令帮助,下面我们再讲解下清单中spec字段中比较常见的字段及其含义 第二章.常用字段讲解 spec.con ...
- nodejs通过mocha处理运行文件路径下所有js文件
1.获取文件路径: 方式一:整个js文件使用 var path=require('path');var public_path=path.resolve('../testcase/listData/* ...
- 3.Jmeter参数化
1.参数化的三种方式 ${变量} 1 用户定义的变量 2 添加配置元件 CSV Data Set Config ,导入.csv文档 3 利用函数助手中的函数获取参数值 主要用 _Random函 ...
- 学习笔记 requests + BeautifulSoup
第一步:requests get请求 # -*- coding:utf-8 -*- # 日期:2018/5/15 17:46 # Author:小鼠标 import requests url = &q ...
- hadoop的hdfs中的javaAPI操作
package cn.itcast.bigdata.hdfs; import java.net.URI; import java.util.Iterator; import java.util.Map ...
- 分布式计算课程补充笔记 part 2
▶ 并行计算八字原则:负载均衡,通信极小 ▶ 并行计算基本形式:主从并行.流水线并行.工作池并行.功能分解.区域分解.递归分治 ▶ MPI 主要理念:进程 (process):无共享存储:显式消息传递 ...
- vue初体验
作为一个前端的小菜鸟,在平时的开发与学习中,除了要深入了解javascript 及 css 的各种特性,熟悉一门框架也是必不可少的.vue以其小巧,轻便,学习平滑等各种特性深受欢迎. 这里总结一下小菜 ...