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_
View Code

相关文章:

  • 2022-12-23
  • 2022-01-31
  • 2021-09-03
  • 2021-07-30
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-05-16
  • 2021-09-24
  • 2022-02-02
  • 2021-09-20
  • 2021-06-18
  • 2021-11-15
  • 2021-08-11
相关资源
相似解决方案