美文网首页
C++ 11 实现类似boost库和Scala的optional

C++ 11 实现类似boost库和Scala的optional

作者: FredricZhu | 来源:发表于2020-12-22 19:29 被阅读0次

    实现原理,
    代码示例是照着《深入应用C++11》抄的。

    1. 使用变长模板参数构造任意对象。
    2. 使用std::aligned_storage实现任意长度对象的内存对齐。
    3. 使用std::forward减少参数拷贝,实现右值引用的完美转发。
      optional.hpp
    #ifndef _OPTIONAL_HPP_
    #define _OPTIONAL_HPP_
    
    #include <type_traits>
    #include <functional>
    
    template <typename T>
    class Optional {
        using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
    
        public:
            Optional() {}
            Optional(const T& v) {
                Create(v);
            }
            
            Optional(T&& v) { 
                Create(std::move(v));
            }
    
            ~Optional() {
                Destroy();
            }
    
            Optional(const Optional& other) {
                if(other.IsInit()) {
                    Assign(other);
                }            
            }
    
            Optional(Optional&& other) {
                if(other.IsInit()) {
                    Assign(std::move(other));
                    other.Destroy();
                }
            }
    
            Optional& operator=(Optional&& other) {
                Assign(std::move(other));
                return *this;
            }
    
            Optional& operator=(const Optional& other) {
                Assign(other);
                return *this;
            }
    
            template <class ... Args> 
            void emplace(Args && ... args) {
                Destroy();
                Create(std::forward<Args>(args)...);
            }
    
            explicit operator bool() const {
                return IsInit();
            }
    
            T& operator*() {
                return *((T*)(&m_data));
            }
    
            T const& operator*() const {
                if(IsInit()) {
                    return *((T*)(&m_data));
                }
                throw std::exception("解引用失败!");
            }
    
            bool operator == (const Optional<T>& rhs) const {
                // 1. 两个对象的初始化状态不等, return false
                // 2. 如果初始化状态相等,当前对象没有被初始化,说明两个对象都没有被初始化,那相等,return true
                // 3. 状态相等,且都被初始化了,比较Optional对象指向的值
                return (!bool(*this)) != (!rhs) ? false: (!bool(*this)) ? true: (*(*this)) == (*rhs); 
            }
    
            bool operator < (const Optional<T>& rhs) const {
                // 1. 如果右值没有初始化, 不可能小于空值,return false
                // 2. 如果右值不为空,左值为空,肯定小于 return true
                // 3. 左值,右值都不为空,比较值
                return !rhs ? false: (!(bool(*this))) ? true: ((*(*this)) < (*rhs));
            }
    
            bool operator != (const Optional<T>& rhs) const {
                return !(*this == (rhs));
            }
    
            bool IsInit() const {
                return m_hasInit;
            }
           
    
        private:
            template <typename... Args>
            void Create(Args&&... args) {
                new (&m_data) T(std::forward<Args>(args)...);
                m_hasInit = true;
            } 
    
            void Destroy() {
                if(m_hasInit) {
                    m_hasInit = false;
                    // 调用T的析构函数释放资源
                    ((T*)(&m_data))->~T();
                }
            }
    
            void Assign(const Optional& other) {
                if(other.IsInit()) {
                    Copy(other.m_data);
                    m_hasInit = true;
                }else {
                    Destroy();
                }
            }
    
            void Assign(Optional&& other) {
                if(other.IsInit()) {
                    Move(std::move(other.m_data));
                    m_hasInit = true;
                    other.Destroy();
                } else {
                    Destroy();
                }
            }
    
            // 调用移动构造函数移动构造
            void Move(data_t&& val) {
                Destroy();
                new (&m_data) T(std::move(*((T*)(&val))));
            } 
    
            void Copy(const data_t& val) {
                Destroy();
                // 直接释放调对象后在原址上用引用值重新分配,会产生拷贝
                new (&m_data) T(*((T*)(&val)));
            }
    
    
    
        private:
            bool m_hasInit = false;
            data_t m_data;
    };
    #endif 
    

    main.cpp测试代码

    #include "optional.hpp"
    #include <iostream>
    #include <string>
    
    using std::cout;
    using std::endl;
    using std::string;
    
    #include <cstdlib>
    
    struct MyStruct {
        MyStruct() {}
    
        MyStruct(int a, int b): m_a(a), m_b(b) {}
        int m_a;
        int m_b;
    };
    
    void testOp() {
        Optional<string> a("ok");
        Optional<string> b("cancel");
        Optional<string> c("aa");
    
        Optional<string> d = a;
        cout << "d=" << *d << endl;
    
        Optional<MyStruct> op;
        op.emplace(1, 2);
    
        MyStruct t;
        if(op) {
            t = *op;
        }
    
        cout << "t.m_a= " << t.m_a << " t.m_b= " << t.m_b << endl; 
        op.emplace(3, 4);
    
        if(op) {
            t = *op;
        }
    
        cout << "t.m_a= " << t.m_a << " t.m_b= " << t.m_b << endl;
    }
    
    int main(void) {
        
        testOp();
    
        cout << "请按任意键继续..." << endl;
        getchar();
        return 0;
    }
    

    Makefile文件代码

    TAR=main
    WORKSPACE_DIR=.
    CC:=g++
    
    .PHONY: build clear all
    
    build:
        $(CC) -std=c++11 $(WORKSPACE_DIR)/optional.hpp $(WORKSPACE_DIR)/main.cpp -g -o $(TAR)
    
    all: clear build
    
    clear:
        rm -rf $(TAR)
    

    测试程序的输出如下,


    图片.png

    相关文章

      网友评论

          本文标题:C++ 11 实现类似boost库和Scala的optional

          本文链接:https://www.haomeiwen.com/subject/rmzsnktx.html