1. any类的实现

(1)any类:

  ①是一个特殊的,只能容纳一个元素的容器,它可以擦除类型可以将何任类型的值赋值给它

  ②使用时,需要根据实际类型将any对象转换为实际的对象

(2)实现any的关键技术

  ①当赋值给any时,需要将值的类型擦除,即以一种通用的方式保存所有类型的数据。通常是通过继承去擦除类型基类是不含模板参数的派生类才含有所要包装对象的类型

  ②赋值时,创建派生类对象赋值给基类指针,派生类携带了数据类型,通过赋值兼容原则擦除了原始数据类型。当需要取数据时,再向下转换成派生类类型,转换失败时抛异常。

  ③由于向any赋值时,会使用原型模式创建出一个派生类对象,这里可以用unique_ptr智能指针来管理该对象的生命期。

  ④设计思路小结:Any内部维护了一个基类指针通过基类指针擦除具体类型any_cast时再通过向下转型获取实际数据。当转型失败时打印详情。

【编程实验】any类的实现

//Any.hpp

#include <memory>
#include <typeindex>
#include <iostream> class Any //注意Any不是一个模板类!但其成员函数可能是个模板函数。
{
private:
//内部类
struct Base;
typedef std::unique_ptr<Base> BasePtr; struct Base //基类不携带被包装对象的类型信息
{
virtual BasePtr Clone() const = ; //设计模式之原型模式
virtual ~Base(){/*std::cout << "virtual ~Base()" << std::endl;*/}
}; template<typename T> //T为被包装对象的类型
struct Derived : Base //派生类
{
public:
T m_value; //被包装的对象
public:
template<typename U>
Derived(U&& value) : m_value(std::forward<U>(value)){} BasePtr Clone() const
{
//由于返回堆对象,所以用智能指针来管理
return BasePtr(new Derived<T>(m_value));
}
};
private:
BasePtr m_ptr; //使用智能指针来管理被包装对象的生命期
std::type_index m_tpIndex; BasePtr Clone() const
{
return (m_ptr == nullptr) ? nullptr : m_ptr->Clone();
}
template<typename T>
using type_origin = typename std::decay<T>::type; public:
template<class U>
bool Is() const
{
return m_tpIndex == std::type_index(typeid(U));
} //注意:std::unique_ptr重载了operator bool()类型转换函数
bool IsNull() const{return !bool(m_ptr);}
public:
Any(void) : m_tpIndex(std::type_index(typeid(void))){}
Any(Any& that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex){}
Any(Any&& that) : m_ptr(std::move(that.Clone())), m_tpIndex(that.m_tpIndex){} //其他类型的被包装对象value(即非Any类),则通过以下构造函数来构造。
//一般需要先通过std::decay类型来移除value的引用和cv属性
template<typename U, class = typename std::enable_if
<!std::is_same<type_origin<U>, Any>::value, U>::type>
Any(U&& value): m_ptr(new Derived<type_origin<U>>(std::forward<U>(value))),
m_tpIndex(std::type_index(typeid(type_origin<U>)))
{
//std::cout << "Any(U&& value)" << std::endl;
} //将Any转换为实际的类型
template<class U>
U& AnyCast()
{
if(!Is<U>()){
std::cout <<"can not cast "<<typeid(U).name()
<<" to " << m_tpIndex.name() << std::endl;
throw std::bad_cast();
} auto derived = dynamic_cast<Derived<U>*>(m_ptr.get());
return derived->m_value;
} //重载赋值操作符
Any& operator=(const Any& a)
{
if(m_ptr != a.m_ptr){
m_ptr = a.Clone(); //unique_ptr指针不能直接赋值给另一个unique_ptr
m_tpIndex = a.m_tpIndex;
}
//std::cout << "Any& operator=(const Any& a)" << std::endl;
return *this;
}
};

//testAny.cpp

#include <iostream>
#include "Any.hpp"
using namespace std; int main()
{
Any n;
auto r = n.IsNull(); //true;
cout << r << endl; string s1 = "hello world!"; n = s1; //先将调用Any(U&&)将s1转为Any类,再赋值给n
cout << n.AnyCast<string>() << endl; n = ; //先将调用Any(U&&)将1转为Any类,再赋值给n
cout << n.AnyCast<int>() << endl;
n.Is<int>(); //true; //n.AnyCast<string>(); //error return ;
}

2. variant类的实现

(1)variant类

  ①类似于union它能代表定义的多种类型,允许赋不同类型的值给它。它的具体类型是在初始化赋值时确定的。

  ②variant用途之一是擦除类型,不同类型的值都统一成一个variant。如variant<int,char,double> vt;表示其可以代表三种类型,但具体哪一种,在初始化时确定。

(2)实现variant的关键技术

  ①找出多种类型中size最大的那个类型,并构造一个内存对齐的缓冲区用于存放variant的值。(见IntegerMax<Types…>::value)

  ②类型检查和缓冲区中创建对象:包含检查赋值的类型是否在己定义的类型中(见Contains<T, Types>::value)以及缓冲区中创建、析构对象。

  ③通过类型取值时,要判断类型是否匹配,如果不匹配,则打印详情。(见Get<T>函数)

  ④通过索引位置获取类型(IndexType函数)和通过类型获取索引位置(get<T>函数)

  ⑤使用访问者模式,定义访问variant各个类型的方法。(见visit函数)

//function_traits.hpp:与上一节相同

#ifndef _FUNCTION_TRAITS_H_
#define _FUNCTION_TRAITS_H_ #include <functional>
#include <tuple> //普通函数
//函数指针
//function/lambda
//成员函数
//函数对象 template<typename T>
struct function_traits; //前向声明 //普通函数
template<typename Ret, typename... Args>
struct function_traits<Ret(Args...)>
{
public:
enum {arity = sizeof...(Args)};//arity : 参数的数量 //函数别名
typedef Ret function_type(Args...); //<==> using function_type = Ret(Args...); typedef Ret return_type; //返回值类型
using stl_function_type = std::function<function_type>;
typedef Ret(*pointer)(Args...); //获取可变参数模板中第I个位置的参数类型。
template<size_t I, class = typename std::enable_if<(I<arity)>::type>
using args = typename std::tuple_element<I, std::tuple<Args...>>;
}; //函数指针
template<typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)>{}; //std::function
template<typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{}; //成员函数
#define FUNCTION_TRAITS(...) \
template <typename ReturnType, typename ClassType, typename... Args> \
struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : function_traits<ReturnType(Args...)>{}; FUNCTION_TRAITS()
FUNCTION_TRAITS(const) //const成员函数
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile) //函数对象
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())>{}; //将lambda转为std::function
template<typename Function>
typename function_traits<Function>::stl_function_type
to_function(const Function& lambda)
{
return static_cast<typename function_traits<Function>::stl_function_type>(std::forward<Function>(lambda));
} template<typename Function>
typename function_traits<Function>::stl_function_type
to_function(Function&& lambda)
{
return static_cast<typename function_traits<Function>::stl_function_type>(lambda);
} //将lambda转为函数指针,如
template<typename Function>
typename function_traits<Function>::pointer
to_function(const Function& lambda)
{
// typedef int(*FUN)(int);
// auto f = FUN([](int x){return x + 10;});
// cout << f(10) << endl; //
return static_cast<typename function_traits<Function>::pointer>(lambda);
} #endif //_FUNCTION_TRAITS_H_

//Variant.hpp

#include <typeindex>
#include <iostream>
#include "function_traits.hpp" /** 获取最大的整数 **/
template<size_t arg, size_t...rest> //eg.IntegerMax<8, 7, 9, 10, 5, 6, 3, 4>::value == 10
struct IntegerMax : std::integral_constant<size_t, (arg > IntegerMax<rest...>::value) ?
arg : IntegerMax<rest...>::value >
{}; template<size_t arg> //递归终止
struct IntegerMax<arg> : std::integral_constant<size_t, arg>
{
}; /** 获取最大的align **/
template<typename... Args> //eg. MaxAlign<char, int, double>::value == 8
struct MaxAlign : std::integral_constant<int, IntegerMax<std::alignment_of<Args>::value...>::value>
{}; /** 是否包含某个类型 **/
template<typename T, typename...List> //eg. Contains<float, char,double,int>::value == 0
struct Contains; template<typename T, typename Head, typename... Rest>
struct Contains<T, Head, Rest...> :
std::conditional<std::is_same<T, Head>::value,
std::true_type,
Contains<T, Rest...> >::type
{}; template<typename T>
struct Contains<T> : std::false_type{}; /**获取T在List中的索引位置**/
//在展开参数包的过程中看是否匹配到特化的IndexOf<T, T, Rest...>,
//如果匹配上则终止递归将之前的value累加起来得到目标类型的索引位置,
//否则将value加1,如果所有的类型中都没有对应的类型则返回-1;
template<typename T, typename... List>
struct IndexOf; //IndexOf<int, double, short, char, int, float>::value == 3 template<typename T, typename Head, typename... Rest>
struct IndexOf<T, Head, Rest...> //T和Head不同
{
private:
enum {temp = IndexOf<T, Rest...>::value };
public:
//enum {value = (temp == -1) ? -1 : temp + 1};
//enum{value = (IndexOf<T, Rest...>::value == -1) ? -1 : IndexOf<T, Rest...>::value + 1 };
enum{value = IndexOf<T, Rest...>::value + };
}; template<typename T, typename... Rest>
struct IndexOf<T, T, Rest...> //T和Head相同
{
enum{value = };
}; template<typename T>
struct IndexOf<T>
{
enum{value = -};
}; /**获取指定位置的类型**/
template<int index, typename... Types> //eg. At<1, int, double, char>::type == double
struct At; template<int index, typename First, typename... Types>
struct At<index, First, Types...>
{
using type = typename At<index-, Types...>::type;
}; template<typename T, typename... Types>
struct At<, T, Types...>
{
using type = T;
}; //Variant类
template<typename... Types>
class Variant
{
enum
{
data_size = IntegerMax<sizeof(Types)...>::value, //类型的最大值
align_size = MaxAlign<Types...>::value //类型最大内存对齐值
};
using data_t = typename std::aligned_storage<data_size, align_size>::type; private:
data_t m_data;
std::type_index m_typeIndex;//类型ID private: //拷贝
void copy(const std::type_index& old_t, const void* old_v, void *new_v)
{
//使用lambda表达式来展开Types...以便根据当前m_typeIndex来判断是否进行拷贝
[&]{std::initializer_list<int>{(copy0<Types>(old_t, old_v, new_v),)...};}();
} template<typename T>
void copy0(const std::type_index& old_t, const void* old_v, void *new_v)
{
if(old_t == std::type_index(typeid(T)))
new (new_v) T (*reinterpret_cast<const T*>(old_v)); //placement new
} //移动
void move(const std::type_index& old_t, void* old_v, void *new_v)
{
//使用lambda表达式来展开Types...以便根据当前m_typeIndex来判断是否进行移动
[&]{std::initializer_list<int>{(move0<Types>(old_t, old_v, new_v),)...};}();
} template<typename T>
void move0(const std::type_index& old_t, void* old_v, void *new_v)
{
if(old_t == std::type_index(typeid(T)))
new (new_v) T (std::move(*reinterpret_cast<T*>(old_v))); //placement new
} //销毁
void destroy(const std::type_index& index, void * buf)
{
[&]{std::initializer_list<int>{(destroy0<Types>(index, buf),)...};}();
} template<typename T>
void destroy0(const std::type_index& index, void * buf)
{
if(index == std::type_index(typeid(T)))
reinterpret_cast<T*>(buf)->~T();
} public:
template<int index>
using IndexType = typename At<index, Types...>::type; Variant(void) : m_typeIndex(typeid(void)){} Variant(const Variant<Types...>& old) : m_typeIndex(old.m_typeIndex)
{
copy(old.m_typeIndex, &old.m_data, &m_data);
} Variant(Variant<Types...>&& old) : m_typeIndex(old.m_typeIndex)
{
move(old.m_typeIndex, &old.m_data, &m_data);
} Variant& operator=(const Variant& old)
{
copy(old.m_typeIndex, &old.m_data, &m_data);
m_typeIndex = old.m_typeIndex;
return *this;
} Variant& operator=(Variant&& old)
{
move(old.m_typeIndex, &old.m_data, &m_data);
m_typeIndex = old.m_typeIndex;
return *this;
} //当Variant被Types...中某一类型的对象初始化时,调用该构造函数
//1. enable_if确保T只能是Types...中的类型,此外,enable_if无第2个参数,则默认为void
template<class T, class = typename std::enable_if<
Contains<typename std::decay<T>::type, Types...>::value>::type>
Variant(T&& value) : m_typeIndex(typeid(void))
{
destroy(m_typeIndex, &m_data); typedef typename std::decay<T>::type U;
new(&m_data) U(std::forward<T>(value));
m_typeIndex = std::type_index(typeid(U));
} ~Variant()
{
destroy(m_typeIndex, &m_data);
} public:
template<typename T>
bool is() const //判断Variant值的类型是否为T
{
return (m_typeIndex == std::type_index(typeid(T)));
} bool Empty()const
{
return m_typeIndex == std::type_index(typeid(void));
} std::type_index type() const //获取类型ID
{
return m_typeIndex;
} //获取元素的值
template<typename T>
typename std::decay<T>::type& get()
{
using U = typename std::decay<T>::type;
if(!is<U>()){
std::cout << typeid(U).name() << " is not defined. "
<< "current type is " << m_typeIndex.name() << std::endl;
throw std::bad_cast{};
}
return *(U*)(&m_data);
} //获取类型的位置索引
template<typename T>
int indexOf()
{
return IndexOf<T, Types...>::value;
} //访问元素(访问者模式)
template<typename F>
void visit(F&& f)
{
//求出F函数的第1个参数的类型(注意由于args也是个模板,需加template)
using T = typename function_traits<F>::template args<>::type; if (is<T>())
f(get<T>()); //获取元素的值,并传入f函数中。
} template<typename F, typename... Rest>
void visit(F&& f, Rest&&... rest)
{
using T = typename function_traits<F>::template args<>::type;
if(is<T>()){
visit(std::forward<F>(f));
}else{
visit(std::forward<Rest>(rest)...);
}
}
};

//testVariant.cpp

#include "Variant.hpp"
#include <iostream> using namespace std; int main()
{
cout << IntegerMax<, , , , , , , >::value << endl; cout << MaxAlign<char, int, double>::value << endl;
cout << sizeof(double) << endl; cout << Contains<float, char, double, int>::value << endl;
cout << IndexOf<float, double, short, char, int>::value << endl; using T = At<, int, double, char>::type;
cout << typeid(T).name() << endl; //输出double typedef Variant<int, double, string, char> V;
V v1 = ; //获取索引位置为1的类型
cout << typeid(V::IndexType<>).name() << endl; //double //获取类型的索引位置
cout << v1.indexOf<string>() << endl; // cout << v1.get<int>() << endl; //10 //是否为空
cout << v1.Empty() << endl; //
cout << v1.type().name() << endl; //int V v2 = v1; //初始化,也可以在这里测试赋值操作
cout << v2.get<int>() << endl; //10 //通过一组lambda访问variant
v1.visit([&](double i){cout << i << endl;},
[&](short i){cout << i << endl;},
[&](int i){cout << i << endl;}, //
[&](string i){cout << i << endl;}); return ;
}

第26课 可变参数模板(7)_any和variant类的实现的更多相关文章

  1. 第27课 可变参数模板(8)_TupleHelper

    1. TupleHelper的主要功能 (1)打印:由于tuple中的元素是可变参数模板,外部并不知道内部到底是什么数据,有时调试时需要知道其具体值,希望能打印出tuple中所有的元素值. (2)根据 ...

  2. 第25课 可变参数模板(6)_function_traits和ScopeGuard的实现

    1. function_traits (1)function_traits的作用:获取函数的实际类型.返回值类型.参数个数和具体类型等.它能获取所有函数语义类型信息.可以获取普通函数.函数指针.std ...

  3. 第24课 可变参数模板(5)_DllHelper和lambda链式调用

    1. dll帮助类 (1)dll的动态链接 ①传统的调用方式:先调用LoadLibrary来加载dll,再定义函数指针类型,接着调用GetProcAddress获取函数地址.然后通过函数指针调用函数, ...

  4. 第23课 可变参数模板(4)_Optional和Lazy类的实现

    1. optional类的实现 (1)optional的功能 ①optional<T>的内部存储空间可能存储了T类型的值,也可能没有.只有当optional被T初始化之后,这个option ...

  5. C++反射机制:可变参数模板实现C++反射

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在Github ...

  6. C++ 0x 使用可变参数模板类 实现 C# 的委托机制

    #ifndef _ZTC_DELEGATE_H_ #define _ZTC_DELEGATE_H_ #include <vector> #include <functional> ...

  7. c++11 可变参数模板类

    c++11 可变参数模板类 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #inc ...

  8. c++11 可变参数模板函数

    c++11 可变参数模板函数 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #in ...

  9. C++反射机制:可变参数模板实现C++反射(使用C++11的新特性--可变模版参数,只根据类的名字(字符串)创建类的实例。在Nebula高性能网络框架中大量应用)

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在码云的仓库地 ...

随机推荐

  1. 网络编程-day1

    一. *** C/S架构:客户端(client)/服务端(server)架构, B/S架构:浏览器(browser) / 服务端(server)架构 软件cs架构:浏览器,qq,微信,陌陌等等 硬件c ...

  2. 曾经觉得学习晦涩难懂的我是如何爱上linux的

    2016年冬天,我已经是一名学习计算机科学与技术专业的大三的“老腊肉”了,但是当时的水平依旧平平.就在2016年快要结束的时候,我周围的同学们被一股考研和工作的压力炸开了锅,我也在默默思考着我的人生, ...

  3. unity 中的UGUI 屏蔽鼠标穿透

    void Update() { if(IsTouchedUI()) { Debug.Log("当前触摸在UI上"); } else { Debug.Log("当前没有触摸 ...

  4. python之路---面向对象编程(二)

    类的继承 1.在python3中,只有新式类,新式类的继承方式为:广度优先.而python2中,经典类的继承方式为:深度优先.那么我们来看看深度优先和广度优先的区别吧 如下图,为类之间的继承关系.B, ...

  5. java中的线程问题(三)——继承Thread VS 实现Runnable的区别

    从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口,如果一定要说它们有什么区别, ...

  6. 数据库编程加入transaction

    TransManager tm = new TransManager(); tm.begin();//开启事物 try { //sql执行代码 // // tm.commit();//更改完sql之后 ...

  7. Alpha冲刺7

    前言 队名:拖鞋旅游队 组长博客:https://www.cnblogs.com/Sulumer/p/10013652.html 作业博客:https://edu.cnblogs.com/campus ...

  8. How to create your iOS team provisioning profile ?

    From Apple Developer: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppS ...

  9. ASP.NET之使用Ajax实现页面异步刷新(无需刷新整个页面)

    目前在使用ASP.NET技术做毕业设计,但是关于网页中的各种配置我到现在还不是很清楚,正在努力进化... 一般情况下,新建网页页面的话,应该为.aspx后缀的文件,建好之后对应一个同名的.cs文件,属 ...

  10. Dubbo的Filter实战--整合Oval校验框架

    前言: 其实很早之前就想写一篇关于oval和具体服务相整合的常见做法, 并以此作为一篇笔记. 趁现在项目中间空闲期, 刚好对dubbo的filter有一些了解. 因此想结合两者, 写一下既结合校验框架 ...