有没有办法在不显式添加的情况下将对 C++ class 成员的引用添加到向量中?
Is there a way to add references to C++ class members to a vector without explicitly adding them?
我正在尝试确定哪些模式可用于以更多 "compositional" 和更少 "imperative" 的方式声明 C++ class。
我正在尝试编写一个包含多个 MyDescriptor
成员的 class。 MyDescriptor
需要由 MyHost
classes 构造函数初始化,它迭代对 MyHost
成员的引用来执行此操作。
有没有办法声明 MyHost
不需要单独添加对容器的 class 成员引用的实现?
class MyDescriptor {
public:
string name;
string fqn;
MyHost(string n) : name(n) {}
void init(string host) {
fqn = host + ":" + name;
}
void do_thing() {
// subclasses to special things.
}
}
class MyHost {
public:
vector<MyDescriptor*> descriptors;
string name
MyHost(string n, vector<MyDescriptor*> d) : name(n),descriptors(d) {
for (MyDescriptor *d : descriptors) {
d->init(name);
}
}
}
MyHostImpl : public MyHost {
public:
// descriptors must be accessible as members like this
MyDescriptor d_1 = MyDescriptor("abc");
MyDescriptor d_2 = MyDescriptor("123");
MyHostImpl(string n) : MyHost(n, {&d_1, &d_2}) {} // This is the issue
void do_thing_1() {
// UPDATE: This is loose example - but what is important to
// know is that developers need to access / use descriptors
// in methods like this.
d_1.do_thing();
}
}
理想情况下,我希望有一种方法可以停止显式声明 descriptors
项目;这个 {&d_1, &d_2}
是我想要消除的。我的团队使用了类似的模式,并且在将描述符添加到 class.
之后不小心没有将描述符添加到向量中而感到沮丧
我不确定你会如何想象它会起作用。 C++ 没有反射,因此您无法遍历它的 class 成员并检查它们的类型。所以,抱歉,就我所知不可能。您当然可以使用一些变通方法,例如直接使用底层基本向量而不是将两个描述符声明为成员变量(您有什么理由需要这样做吗?),然后将它们隐式传递到 Base 构造函数中,但是您重新瞄准是不可能的。
编辑:显然可以使用一些黑暗巫毒魔法,请参阅下面的评论。
是的,有一种方法可以直接满足您的要求,至少在 C++14 中是这样,但它涉及到一堆黑巫术。在本次会议 C++ 2018 演讲中:
Better C++14 reflections - Antony Polukhin
Antony 解释了如何能够遍历结构的所有成员并访问其类型。他使用它在某些输出流上打印值,但您可以使用相同的方法将地址推回 std::vector<MyDescriptor*>
.
话虽如此 - 我认为您应该避免这种模式。只需首先创建一个 MyDescriptors 向量,然后使用对该向量的引用即可。为什么要使用需要如此多扭曲才能产生的指针向量?
反转构造函数语义。让描述符的构造函数获取宿主引用并将其自身添加到宿主向量,而不是宿主构造函数接受描述符指针:
MyDescriptor::MyDescriptor(MyDescriptor const&)=delete;
auto& MyDescriptor::operator=(MyDescriptor const&)=delete;
MyDescriptor::MyDescriptor(string n, MyHost& h): name{n},fqn{n+":"+h.get_name()}
{
h.add(this);
};
MyHost::MyHost(string n):name{n}{};
void MyHost::add(MyDescriptor* d){
descriptors.push_back(d);
};
auto& MyHost::get_name()const{
return name;
};
这样你就不会忘记给主机添加描述符否则编译器会哭。
MyHostImpl::MyHostImpl(string n):
MyHost{n},
d_1{"abc",*this},/*compiler kills you if you forget this line*/
d_2{"123",*this}/*compiler kills you if you forget this line*/
{};
我正在尝试确定哪些模式可用于以更多 "compositional" 和更少 "imperative" 的方式声明 C++ class。
我正在尝试编写一个包含多个 MyDescriptor
成员的 class。 MyDescriptor
需要由 MyHost
classes 构造函数初始化,它迭代对 MyHost
成员的引用来执行此操作。
有没有办法声明 MyHost
不需要单独添加对容器的 class 成员引用的实现?
class MyDescriptor {
public:
string name;
string fqn;
MyHost(string n) : name(n) {}
void init(string host) {
fqn = host + ":" + name;
}
void do_thing() {
// subclasses to special things.
}
}
class MyHost {
public:
vector<MyDescriptor*> descriptors;
string name
MyHost(string n, vector<MyDescriptor*> d) : name(n),descriptors(d) {
for (MyDescriptor *d : descriptors) {
d->init(name);
}
}
}
MyHostImpl : public MyHost {
public:
// descriptors must be accessible as members like this
MyDescriptor d_1 = MyDescriptor("abc");
MyDescriptor d_2 = MyDescriptor("123");
MyHostImpl(string n) : MyHost(n, {&d_1, &d_2}) {} // This is the issue
void do_thing_1() {
// UPDATE: This is loose example - but what is important to
// know is that developers need to access / use descriptors
// in methods like this.
d_1.do_thing();
}
}
理想情况下,我希望有一种方法可以停止显式声明 descriptors
项目;这个 {&d_1, &d_2}
是我想要消除的。我的团队使用了类似的模式,并且在将描述符添加到 class.
我不确定你会如何想象它会起作用。 C++ 没有反射,因此您无法遍历它的 class 成员并检查它们的类型。所以,抱歉,就我所知不可能。您当然可以使用一些变通方法,例如直接使用底层基本向量而不是将两个描述符声明为成员变量(您有什么理由需要这样做吗?),然后将它们隐式传递到 Base 构造函数中,但是您重新瞄准是不可能的。
编辑:显然可以使用一些黑暗巫毒魔法,请参阅下面的评论。
是的,有一种方法可以直接满足您的要求,至少在 C++14 中是这样,但它涉及到一堆黑巫术。在本次会议 C++ 2018 演讲中:
Better C++14 reflections - Antony Polukhin
Antony 解释了如何能够遍历结构的所有成员并访问其类型。他使用它在某些输出流上打印值,但您可以使用相同的方法将地址推回 std::vector<MyDescriptor*>
.
话虽如此 - 我认为您应该避免这种模式。只需首先创建一个 MyDescriptors 向量,然后使用对该向量的引用即可。为什么要使用需要如此多扭曲才能产生的指针向量?
反转构造函数语义。让描述符的构造函数获取宿主引用并将其自身添加到宿主向量,而不是宿主构造函数接受描述符指针:
MyDescriptor::MyDescriptor(MyDescriptor const&)=delete;
auto& MyDescriptor::operator=(MyDescriptor const&)=delete;
MyDescriptor::MyDescriptor(string n, MyHost& h): name{n},fqn{n+":"+h.get_name()}
{
h.add(this);
};
MyHost::MyHost(string n):name{n}{};
void MyHost::add(MyDescriptor* d){
descriptors.push_back(d);
};
auto& MyHost::get_name()const{
return name;
};
这样你就不会忘记给主机添加描述符否则编译器会哭。
MyHostImpl::MyHostImpl(string n):
MyHost{n},
d_1{"abc",*this},/*compiler kills you if you forget this line*/
d_2{"123",*this}/*compiler kills you if you forget this line*/
{};