Объявление / переопределение конфликтов: разные основные типы - PullRequest
0 голосов
/ 03 июля 2018

Я пытаюсь использовать вариационный шаблонный класс для создания структуры родительско-дочерних отношений.

#include <tuple>

template<typename TParentTuple, typename TChilderenTuple>
class Obj;

template<typename... TParents, typename... TChildren>
class Obj<std::tuple<TParents...>, std::tuple<TChildren...>> {
private:
    std::tuple<std::vector<std::shared_ptr<TParents...>>> parentsVectors;
    std::tuple<std::vector<std::shared_ptr<TChildren...>>> childrenVectors;
};


using Tree = Obj<std::tuple<>, std::tuple<>>;
using Dog = Obj<std::tuple<>, std::tuple<>>;
using Parasite = Obj<std::tuple<>, std::tuple<>>;

using Human = Obj<std::tuple<>,std::tuple<Tree, Dog>>;
using Tree = Obj<std::tuple<Human>, std::tuple<>>;
using Dog = Obj<std::tuple<Human>, std::tuple<Parasite>>;
using Parasite = Obj<std::tuple<Dog>, std::tuple<>>;

int main() {}

Это дает мне такую ​​ошибку в MSVS2017:

ошибка C2371: «Дерево»: переопределение; различные основные типы

И это в GCC:

ошибка: конфликтующее объявление

Я искал во всем Интернете, как это исправить, но пока не нашел. Это поправимо?

редактирование:

То, что я действительно пытаюсь сделать, - это использовать метапрограммирование, чтобы помешать мне писать много повторяющегося кода, как я делал в этот ответ

edit2:

Хорошо, давайте расширимся. Связь объясняется в этом вопросе

Я писал Human Dog и т. Д. Классы, такие как

Human.hpp

#include "BaseObject.hpp"
#include "Tree.hpp"
#include "Dog.hpp"
class Tree;
class Dog;

class Human : public BaseObject {
public:
    prtVector<BaseObject> getAllParents() const override;
    prtVector<BaseObject> getAllChildren() const override;

    void removeAllParents() override;
    void removeAllChildren() override ;

    friend class Dog;
    friend class Tree;
    template<class A, class B>
    friend void addRelation(A* a, B* b);
private:
    void addParent(Human* const);
    void removeParent(Human const* const);
    void addChild(Human* const);
    void removeChild(Human const* const);
    void addChild(Tree* const);
    void removeChild(Tree const* const);
    void addChild(Dog* const);
    void removeChild(Dog const* const);
private:
    prtVector<Human> parents;
    prtVector<Human> children;
    prtVector<Tree> plants;
    prtVector<Dog> pets;
};

Human.cpp

#include "Human.hpp"

prtVector<BaseObject> Human::getAllParents() const {
    prtVector<BaseObject> result(std::cbegin(parents), std::cend(parents));
    return result;
}

prtVector<BaseObject> Human::getAllChildren() const {
    prtVector<BaseObject> result(std::cbegin(children), std::cend(children));
    result.insert(std::end(result), std::cbegin(pets), std::cend(pets));
    result.insert(std::end(result), std::cbegin(plants), std::cend(plants));
    return result;
}

void Human::removeAllParents() {
    for (auto parent : parents) { parent->removeChild(this); }
    parents.clear();
}

void Human::removeAllChildren() {
    for (auto child : children) { child->removeParent(this); } children.clear();
    for (auto pet : pets) { pet->removeParent(this); } pets.clear();
    for (auto plant : plants) { plant->removeParent(this); } plants.clear();
}

void Human::addParent(Human* const parent) { parents.push_back(parent); }

#include <algorithm>
void Human::removeParent(Human const* const parent) {
    auto it = std::find(std::cbegin(parents), std::cend(parents), parent);
    if (it != std::cend(parents)) parents.erase(it);
}
void Human::addChild(Human* const child) { children.push_back(child); }

void Human::removeChild(Human const* const child) {
    auto it = std::find(std::cbegin(children), std::cend(children), child);
    if (it != std::cend(children)) children.erase(it);
}
void Human::addChild(Dog* const pet) { pets.push_back(pet); }

void Human::removeChild(Dog const* const pet) {
    auto it = std::find(std::cbegin(pets), std::cend(pets), pet);
    if (it != std::cend(pets)) pets.erase(it);
}
void Human::addChild(Tree* const plant) { plants.push_back(plant); }

void Human::removeChild(Tree const* const plant) {
    auto it = std::find(std::cbegin(plants), std::cend(plants), plant);
    if (it != std::cend(plants)) plants.erase(it);
}

То же самое для Dog: Dog.hpp

#include "BaseObject.hpp"
#include "Human.hpp"
#include "Parasite.hpp"
class Human;
class Parasite;

class Dog : public BaseObject {
public:
    prtVector<BaseObject> getAllParents() const override;
    prtVector<BaseObject> getAllChildren() const override;

    void removeAllParents() override;
    void removeAllChildren() override;

    friend class Human;
    friend class Parasite;
    template<class A, class B>
    friend void addRelation(A* a, B* b);
private:
    void addParent(Human* const);
    void removeParent(Human const* const);
    void addChild(Parasite* const);
    void removeChild(Parasite const* const);
private:
    prtVector<Human> owners;
    prtVector<Parasite> parasites;
};

Dog.cpp

#include "Dog.hpp"

prtVector<BaseObject> Dog::getAllParents() const {
    prtVector<BaseObject> result(std::cbegin(owners), std::cend(owners));
    return result;
}

prtVector<BaseObject> Dog::getAllChildren() const {
    prtVector<BaseObject> result(std::cbegin(parasites), std::cend(parasites));
    return result;
}

void Dog::removeAllParents() {
    for (auto owner : owners) { owner->removeChild(this); }
    owners.clear();
}

void Dog::removeAllChildren() {
    for (auto parasite : parasites) { parasite->removeParent(this); }
    parasites.clear();
}

void Dog::addParent(Human* const owner) { owners.push_back(owner); }

#include <algorithm>
void Dog::removeParent(Human const* const owner) {
    auto it = std::find(std::cbegin(owners), std::cend(owners), owner);
    if (it != std::cend(owners)) owners.erase(it);
}

void Dog::addChild(Parasite* const parasite) { parasites.push_back(parasite); }

void Dog::removeChild(Parasite const* const parasite) {
    auto it = std::find(std::cbegin(parasites), std::cend(parasites), parasite);
    if (it != std::cend(parasites)) parasites.erase(it);
}

И так далее для Tree и Parasite. Как видите, там много повторяющегося кода! Я думал, что метапрограммирование должно помочь мне в этом: создание функций для определенных типов, передаваемых в качестве аргументов шаблона переменной.

1 Ответ

0 голосов
/ 03 июля 2018

Я думаю, что вижу, чего вы пытаетесь достичь, и я верю, что вы можете достичь этого, используя типы тегов:

template<typename TParentTuple, typename TChilderenTuple>
class Obj;

template<typename TParents, typename TChildren>
class Obj<std::tuple<TParents>, std::tuple<TChildren>> {};

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<>>;

Скорее всего, вы натолкнетесь на какой-нибудь другой рекурсивный беспорядок.

Редактировать: развернуть код, чтобы показать, как отобразить тег обратно на типы:

#include <tuple>
#include <vector>

template<typename TParentTuple, typename TChilderenTuple>
class Obj;

template<typename... TParents, typename... TChildren>
class Obj<std::tuple<TParents...>, std::tuple<TChildren...>> {
public:
  std::tuple<std::vector<typename TParents::obj_type*>...> parents_;
  std::tuple<std::vector<typename TChildren::obj_type*>...> children_;
};

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;
};

void foo() {
    Tree t;
    Human h;

    std::get<0>(t.parents_).emplace_back(&h);
}
...