代码之家  ›  专栏  ›  技术社区  ›  JHBonarius

获取此对象的原始类型

  •  1
  • JHBonarius  · 技术社区  · 6 年前

    我试图使用元编程来防止父子结构中的代码重复。我在一定程度上解决了这个问题。

    底部编译器和runt中显示的代码正确,但有些关系( /*Tree_tag,*/ /*Parasite_tag*/ )被注释掉。如果未注释,MSVS2017显示

    error C2664: 'void Obj<std::tuple<Human_tag>,std::tuple<>>::removeParent(const Obj<std::tuple<>,std::tuple<Tree_tag,Dog_tag>> *const )': cannot convert argument 1 from 'Obj<std::tuple<>,std::tuple<Dog_tag>> *' to 'const Obj<std::tuple<>,std::tuple<Tree_tag,Dog_tag>> *const '
    note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
    

    G++显示

    In instantiation of ‘void Obj<std::tuple<>, std::tuple<_El0, _El ...> ::removeAllChildren() [with TChildTag = Dog_tag; TChildTags = {}]’:
    Main.cpp:126:1:   required from here
    Main.cpp:73:43: error: invalid conversion from ‘Obj<std::tuple<>, std::tuple<Dog_tag> >*’ to ‘const TParent* {aka const Obj<std::tuple<>, std::tuple<Tree_tag, Dog_tag> >*}’ [-fpermissive]
        for (auto&& child : childrenPtrs) child->removeParent(this);
    

    问题出在 this 类型限定符。因为我迭代地去掉模板参数,例如

    class Obj<std::tuple<>, std::tuple<TChildTag, TChildTags...>>
    : public Obj<std::tuple<>, std::tuple<TChildTags...>>
    

    结果 基类型的与原始类型不匹配。就像错误显示的那样:原始类型 Human = Obj<std::tuple<>,std::tuple<Tree_tag,Dog_tag>> .但是,由于迭代剥离,因此 在基地是 Obj<std::tuple<>,std::tuple<Dog_tag>> .

    我试着用 reinterpret_cast 如建议:

    template<typename T>
    void addParent(T* const parentPtr) {
        parentsPtrs.push_back(reinterpret_cast<TParent* const>(parentPtr));
    }
    template<typename T>
    void removeParent(T const* const parentPtr) {
        auto it = std::find(std::cbegin(parentsPtrs), std::cend(parentsPtrs),
            reinterpret_cast<TParent const* const>(parentPtr));
        if (it != std::cend(parentsPtrs)) parentsPtrs.erase(it);
    }
    

    但问题是 一切 转换为允许的参数。即,本规范适用于:

    int main() {
        Human h1;
        Parasite p1;
        addRelation(&h1, &p1);
    }
    

    …这是不可能的,因为 人类 Parasite 不直接相关。

    那么我怎样才能正确地保存 顶级(最派生)类的类型限定符,符合 人类 ,请 Dog 等类型?

    工作代码(带注释):

    #include <tuple>
    #include <vector>
    
    template<class T>
    using prtVector = std::vector<T*>;
    
    class BaseObject {
    public:
        virtual prtVector<BaseObject> getAllParents() const = 0;
        virtual prtVector<BaseObject> getAllChildren() const = 0;
        virtual void removeAllParents() = 0;
        virtual void removeAllChildren() = 0;
    };
    
    template<typename TParentTuple, typename TChilderenTuple>
    class Obj;
    
    template<typename TParentTag, typename... TParentTags, typename... TChildTags>
    class Obj<std::tuple<TParentTag, TParentTags...>, std::tuple<TChildTags...>>
        : public Obj<std::tuple<TParentTags...>, std::tuple<TChildTags...>>
    {
        using TParent = typename TParentTag::obj_type;
        prtVector<TParent> parentsPtrs;
    public:
        void addParent(TParent* const parentPtr) { parentsPtrs.push_back(parentPtr); }
        void removeParent(TParent const* const parentPtr) {
            auto it = std::find(std::cbegin(parentsPtrs), std::cend(parentsPtrs), parentPtr);
            if (it != std::cend(parentsPtrs)) parentsPtrs.erase(it);
        }
    
        virtual prtVector<BaseObject> getAllParents() const override {
            auto result = Obj<std::tuple<TParentTags...>, std::tuple<TChildTags...>>::getAllParents();
            result.insert(std::begin(result), std::cbegin(parentsPtrs), std::cend(parentsPtrs));
            return result;
        }
        virtual prtVector<BaseObject> getAllChildren() const override {
            return Obj<std::tuple<TParentTags...>, std::tuple<TChildTags...>>::getAllChildren();
        }
        virtual void removeAllParents() override {
            Obj<std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeAllParents();
            for (auto&& parent : parentsPtrs) parent->removeChild(this);
        }
        virtual void removeAllChildren() override {
            Obj<std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeAllChildren();
        }
    };
    
    template<typename TChildTag, typename... TChildTags>
    class Obj<std::tuple<>, std::tuple<TChildTag, TChildTags...>>
        : public Obj<std::tuple<>, std::tuple<TChildTags...>>
    {
        using TChild = typename TChildTag::obj_type;
        prtVector<TChild> childrenPtrs;
    public:
        void addChild(TChild* const childPtr) { childrenPtrs.push_back(childPtr); }
        void removeChild(TChild const* const childPtr) {
            auto it = std::find(std::cbegin(childrenPtrs), std::cend(childrenPtrs), childPtr);
            if (it != std::cend(childrenPtrs)) childrenPtrs.erase(it);
        }
    
        virtual prtVector<BaseObject> getAllParents() const override {
            return Obj<std::tuple<>, std::tuple<TChildTags...>>::getAllChildren();
        }
        virtual prtVector<BaseObject> getAllChildren() const override {
            auto result = Obj<std::tuple<>, std::tuple<TChildTags...>>::getAllChildren();
            result.insert(std::begin(result), std::cbegin(childrenPtrs), std::cend(childrenPtrs));
            return result;
        }
        virtual void removeAllParents() override {}
        virtual void removeAllChildren() override {
            Obj<std::tuple<>, std::tuple<TChildTags...>>::removeAllChildren();
            for (auto&& child : childrenPtrs) child->removeParent(this);
        }
    };
    
    template<>
    class Obj<std::tuple<>, std::tuple<>> : public BaseObject {
    public:
        virtual prtVector<BaseObject> getAllParents() const override {
            return prtVector<BaseObject>();
        }
        virtual prtVector<BaseObject> getAllChildren() const override {
            return prtVector<BaseObject>();
        }
        virtual void removeAllParents() override {}
        virtual void removeAllChildren() override {}
    };
    
    struct Human_tag;
    struct Tree_tag;
    struct Dog_tag;
    struct Parasite_tag;
    
    using Human = Obj<std::tuple<>, std::tuple</*Tree_tag,*/ Dog_tag>>;
    using Tree = Obj<std::tuple<Human_tag>, std::tuple<>>;
    using Dog = Obj<std::tuple<Human_tag>, std::tuple</*Parasite_tag*/>>;
    using Parasite = Obj<std::tuple<Dog_tag>, std::tuple<>>;
    
    struct Human_tag { using obj_type = Human; };
    struct Tree_tag { using obj_type = Tree; };
    struct Dog_tag { using obj_type = Dog; };
    struct Parasite_tag { using obj_type = Parasite; };
    
    template<class A, class B>
    void addRelation(A* a, B* b)
    {
        a->addChild(b);
        b->addParent(a);
    }
    
    #include <iostream>
    int main() {
        Human h1;
        Dog d1, d2;
    
        addRelation(&h1, &d1);
        addRelation(&h1, &d2);
        auto result = h1.getAllChildren();
        std::cout << result.size() << "\n"; //print 2
        d1.removeAllParents();
        result = h1.getAllChildren();
        std::cout << result.size() << "\n"; //print 1
    
        std::cin.ignore();
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Jarod42    6 年前

    template<typename TParentTuple, typename TChilderenTuple>
    class Obj;
    
    template<typename... ParentTags,
             typename... ChildTags>
    class Obj<std::tuple<ParentTags...>, std::tuple<ChildTags...>> : public BaseObject
    {
        std::tuple<std::vector<typename ParentTags::obj_type*>...> parents;
        std::tuple<std::vector<typename ChildTags::obj_type*>...> children;
    
    public:
    
        template <typename T>
        void addParent(T* parent) { std::get<std::vector<T*>>(parents).push_back(parent); }
    
        template <typename T>
        void removeParent(const T* parent) {
            auto& v = std::get<std::vector<T*>>(parents);
            auto it = std::find(std::cbegin(v), std::cend(v), parent);
            if (it != std::cend(v)) { v.erase(it); }
        }
    
        template <typename T>
        void addChild(T* child) { std::get<std::vector<T*>>(children).push_back(child); }
    
        template <typename T>
        void removeChild(const T* child) {
            auto& v = std::get<std::vector<T*>>(children);
            auto it = std::find(std::cbegin(v), std::cend(v), child);
            if (it != std::cend(v)) { v.erase(it); }
        }
    
        std::vector<BaseObject*> getAllParents() const override {
            std::vector<BaseObject*> res;
    
            std::apply([&](auto&... v){ (res.insert(res.end(), v.begin(), v.end()), ...); },
                       parents);
            return res;
        }
        std::vector<BaseObject*> getAllChildren() const override {
            std::vector<BaseObject*> res;
    
            std::apply([&](auto&... v){ (res.insert(res.end(), v.begin(), v.end()), ...); },
                       children);
            return res;
        }
    
        void removeAllParents() override {
            std::apply(
                [this](auto&... v)
                {
                    [[maybe_unused]] auto clean = [this](auto& v) {
                        for (auto* parent : v) {
                            parent->removeChild(this);
                        }
                        v.clear();
                    };
                    (clean(v), ...);
                },
                parents);
        }
    
        void removeAllChildren() override {
            std::apply(
                [this](auto&... v)
                {
                    [[maybe_unused]] auto clean = [this](auto& v) {
                        for (auto* child : v) {
                            child->removeParent(this);
                        }
                        v.clear();
                    };
                    ( clean(v), ...);
                },
                children);
        }
    };
    

    Demo

    std::apply

    std::get<T>(tuple)

        2
  •  0
  •   JHBonarius    6 年前

    template<typename TOwnTag, typename TParentTag, typename... TParentTags, typename... TChildTags>
    class Obj<TOwnTag, std::tuple<TParentTag, TParentTags...>, std::tuple<TChildTags...>>
        : public Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>
    {
        using TOwn = typename TOwnTag::obj_type;
    

    reinterpret_cast<TOwn* const>(this)
    

    #include <tuple>
    #include <vector>
    #include <algorithm>
    
    template<class T>
    using prtVector = std::vector<T*>;
    
    class BaseObject {
    public:
        virtual prtVector<BaseObject> getAllParents() const = 0;
        virtual prtVector<BaseObject> getAllChildren() const = 0;
        virtual void removeAllParents() = 0;
        virtual void removeAllChildren() = 0;
    };
    
    template<typename TOwnTag, typename TParentTuple, typename TChilderenTuple>
    class Obj;
    
    template<typename TOwnTag, typename TParentTag, typename... TParentTags, typename... TChildTags>
    class Obj<TOwnTag, std::tuple<TParentTag, TParentTags...>, std::tuple<TChildTags...>>
        : public Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>
    {
        using TOwn = typename TOwnTag::obj_type;
        using TParent = typename TParentTag::obj_type;
        prtVector<TParent> parentsPtrs;
    public:
        //prevent base function hiding
        using Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::addParent;
        using Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeParent;
    
        void addParent(TParent* const parentPtr) { parentsPtrs.push_back(parentPtr); }
        void removeParent(TParent const* const parentPtr) {
            auto it = std::find(std::cbegin(parentsPtrs), std::cend(parentsPtrs), parentPtr);
            if (it != std::cend(parentsPtrs)) parentsPtrs.erase(it);
        }
    
        virtual prtVector<BaseObject> getAllParents() const override {
            auto result = Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::getAllParents();
            result.insert(std::begin(result), std::cbegin(parentsPtrs), std::cend(parentsPtrs));
            return result;
        }
        virtual prtVector<BaseObject> getAllChildren() const override {
            return Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::getAllChildren();
        }
        virtual void removeAllParents() override {
            Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeAllParents();
            for (auto&& parent : parentsPtrs) parent->removeChild(reinterpret_cast<TOwn* const>(this));
        }
        virtual void removeAllChildren() override {
            Obj<TOwnTag, std::tuple<TParentTags...>, std::tuple<TChildTags...>>::removeAllChildren();
        }
    };
    
    template<typename TOwnTag, typename TChildTag, typename... TChildTags>
    class Obj<TOwnTag, std::tuple<>, std::tuple<TChildTag, TChildTags...>>
        : public Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>
    {
        using TOwn = typename TOwnTag::obj_type;
        using TChild = typename TChildTag::obj_type;
        prtVector<TChild> childrenPtrs;
    public:
        void addParent() {}
        void removeParent() {}
        //prevent base function hiding
        using Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::addChild;
        using Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::removeChild;
    
        void addChild(TChild* const childPtr) { childrenPtrs.push_back(childPtr); }
        void removeChild(TChild const* const childPtr) {
            auto it = std::find(std::cbegin(childrenPtrs), std::cend(childrenPtrs), childPtr);
            if (it != std::cend(childrenPtrs)) childrenPtrs.erase(it);
        }
    
        virtual prtVector<BaseObject> getAllParents() const override {
            return Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::getAllParents();
        }
        virtual prtVector<BaseObject> getAllChildren() const override {
            auto result = Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::getAllChildren();
            result.insert(std::begin(result), std::cbegin(childrenPtrs), std::cend(childrenPtrs));
            return result;
        }
        virtual void removeAllParents() override {}
        virtual void removeAllChildren() override {
            Obj<TOwnTag, std::tuple<>, std::tuple<TChildTags...>>::removeAllChildren();
            for (auto&& child : childrenPtrs) child->removeParent(reinterpret_cast<TOwn* const>(this));
        }
    };
    
    template<typename TOwnTag>
    class Obj<TOwnTag, std::tuple<>, std::tuple<>> : public BaseObject {
    public:
        void addChild() {}
        void removeChild() {}
        void addParent() {}
        void removeParent() {}
        //
        virtual prtVector<BaseObject> getAllParents() const override {
            return prtVector<BaseObject>();
        }
        virtual prtVector<BaseObject> getAllChildren() const override {
            return prtVector<BaseObject>();
        }
        virtual void removeAllParents() override {}
        virtual void removeAllChildren() override {}
    };
    
    struct Human_tag;
    struct Tree_tag;
    struct Dog_tag;
    struct Parasite_tag;
    
    using Human = Obj<Human_tag, std::tuple<>, std::tuple<Tree_tag, Dog_tag>>;
    using Tree = Obj<Tree_tag, std::tuple<Human_tag>, std::tuple<>>;
    using Dog = Obj<Dog_tag, std::tuple<Human_tag>, std::tuple<Parasite_tag>>;
    using Parasite = Obj<Parasite_tag, std::tuple<Dog_tag>, std::tuple<>>;
    
    struct Human_tag { using obj_type = Human; };
    struct Tree_tag { using obj_type = Tree; };
    struct Dog_tag { using obj_type = Dog; };
    struct Parasite_tag { using obj_type = Parasite; };
    
    template<class A, class B>
    void addRelation(A* const a, B* const b)
    {
        a->addChild(b);
        b->addParent(a);
    }
    
    #include <iostream>
    int main() {
        Human h1;
        Dog d1, d2;
        //Parasite p1;
    
        addRelation(&h1, &d1);
        addRelation(&h1, &d2);
        //addRelation(&h1, &p1); // compiler error
        auto result = h1.getAllChildren();
        std::cout << result.size() << "\n"; //print 2
        d1.removeAllParents();
        result = h1.getAllChildren();
        std::cout << result.size() << "\n"; //print 1
    
        std::cin.ignore();
    }
    

    Live Example