首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >正在获取此对象的原始类型

正在获取此对象的原始类型
EN

Stack Overflow用户
提问于 2018-07-04 20:07:08
回答 2查看 62关注 0票数 1

我正在尝试使用元编程来防止父子结构中的重复代码。我让它工作到了一定的程度。

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

代码语言:javascript
复制
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++展示

代码语言:javascript
复制
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类型限定符上。因为我迭代地剥离了模板参数,例如

代码语言:javascript
复制
class Obj<std::tuple<>, std::tuple<TChildTag, TChildTags...>>
: public Obj<std::tuple<>, std::tuple<TChildTags...>>

基类型的结果this与原始类型不匹配。如错误所示:原始类型的Human = Obj<std::tuple<>,std::tuple<Tree_tag,Dog_tag>>。但是,由于迭代剥离,基础中的this类型是Obj<std::tuple<>,std::tuple<Dog_tag>>

我尝试按照建议使用reinterpret_cast

代码语言:javascript
复制
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);
}

但接下来的问题是,everything被强制转换为一个允许的参数。也就是说,下面的代码是有效的:

代码语言:javascript
复制
int main() {
    Human h1;
    Parasite p1;
    addRelation(&h1, &p1);
}

...Which应该是不可能的,因为HumanParasite不是直接相关的。

那么,我如何正确地保持顶级(最派生的)类的this类型限定符符合HumanDog等类型呢?

工作代码(带注释):

代码语言:javascript
复制
#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();
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-05 03:52:44

使用C++17,您可以执行以下操作(不使用cast):

代码语言:javascript
复制
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

有了C++14,用std::apply和折叠表达式代替"for_each_tuple“会更冗长。

在C++11中,使用std::get<T>(tuple)更是如此。

票数 1
EN

Stack Overflow用户

发布于 2018-07-04 21:04:06

好的,我对此考虑了很多,并决定将原始类型添加为另一个模板参数。因此,类签名将类似于:

代码语言:javascript
复制
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;

这似乎解决了我的问题,因为我现在可以使用

代码语言:javascript
复制
reinterpret_cast<TOwn* const>(this)

然后,完整的工作代码变成:

代码语言:javascript
复制
#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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51173345

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档