我正在尝试使用可变参数模板类来构建父子关系。
#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中:
错误:声明冲突
我一直在网上寻找如何解决此问题的方法,但还没有找到。这个可以解决吗?
我真正想要做的是像使用this answer
一样,使用元编程来阻止我编写很多重复的代码。好,让我们扩展。该关系在this question
中进行了说明我一直在写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
依此类推。
如您所见,其中有很多重复的代码!我当时以为元编程应该能够为我提供帮助:为作为可变参数模板参数传递的特定类型生成函数。
答案 0 :(得分:2)
我想我明白了您要完成的工作,并且相信您可以使用代码类型到达那里:
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);
}