Есть ли способ добавить ссылки на члены класса C ++ в вектор, не добавляя их явно? - PullRequest
1 голос
/ 10 марта 2019

Я пытаюсь определить, какие шаблоны могут быть использованы для объявления класса C ++ более «композиционным» и менее «императивным» способом.

Я пытаюсь написать класс, который включает несколько MyDescriptor членов. MyDescriptor должен быть инициализирован конструктором классов MyHost, и для этого он перебирает ссылки на члены MyHost.

Есть ли способ объявить MyHost реализации, которые не требуют добавления ссылок на члены класса в контейнер отдельно?

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} это то, что я хотел бы устранить. Моя команда использует похожий шаблон и постоянно разочаровывается тем, что случайно не добавляет дескрипторы в вектор после добавления его в класс.

Ответы [ 3 ]

3 голосов
/ 10 марта 2019

Инвертировать семантику ctor. Вместо того, чтобы ctor хоста принимал указатели дескриптора, пусть ctor дескриптора берет ссылку на хост и добавляет себя к вектору хоста:

    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*/
{};
0 голосов
/ 10 марта 2019

Да, есть способ сделать напрямую то, что вы просите, по крайней мере, в C ++ 14, но он включает в себя кучу темного вуду. На этом совещании C ++ 2018 говорить:

Лучше C ++ 14 отражений - Антоний Полухин

Антоний объясняет, как можно перебирать всех членов структуры с доступом к их типам. Он использует его для печати значений в некотором выходном потоке, но вы можете использовать тот же метод для возврата адресов в std::vector<MyDescriptor*>.

Сказав это, я думаю, вы должны просто избегать этого паттерна. Просто создайте вектор MyDescriptors для начала и работайте со ссылкой на это. Зачем использовать вектор указателей, который требует столько искажений для создания?

0 голосов
/ 10 марта 2019

Я не уверен, как вы себе это представляете. C ++ не имеет никакого отражения, поэтому у вас нет возможности перебирать его членов класса и проверять их тип. Так что, извините, это невозможно для всех, кого я знаю. Конечно, вы можете использовать некоторые обходные пути, например, просто использовать базовый базовый вектор напрямую, вместо того, чтобы объявлять два дескриптора в качестве переменных-членов (есть ли какая-то причина, по которой вам это нужно?), А затем неявно передавать их в конструктор Base, но что вы Перецель не возможен.

Редактировать: Очевидно, это возможно с некоторой темной магией вуду, см. Комментарий ниже.

...