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 = 0; //设计模式之原型模式 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 = 100; //先将调用Any(U&&)将1转为Any类,再赋值给n cout << n.AnyCast<int>() << endl; n.Is<int>(); //true; //n.AnyCast<string>(); //error return 0; }
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; //20 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 + 1 }; }; template<typename T, typename... Rest> struct IndexOf<T, T, Rest...> //T和Head相同 { enum{value = 0}; }; template<typename T> struct IndexOf<T> { enum{value = -1}; }; /**获取指定位置的类型**/ 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-1, Types...>::type; }; template<typename T, typename... Types> struct At<0, 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),0)...};}(); } 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),0)...};}(); } 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),0)...};}(); } 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<0>::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<0>::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<8, 7, 9, 10, 5, 6, 3, 4>::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<1, int, double, char>::type; cout << typeid(T).name() << endl; //输出double typedef Variant<int, double, string, char> V; V v1 = 10; //获取索引位置为1的类型 cout << typeid(V::IndexType<1>).name() << endl; //double //获取类型的索引位置 cout << v1.indexOf<string>() << endl; //2 cout << v1.get<int>() << endl; //10 //是否为空 cout << v1.Empty() << endl; //0 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;}, //10 [&](string i){cout << i << endl;}); return 0; }