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_