повышение:сигнал2: используйте общедоступный сигнал классов в его конструкторе

#c #boost

Вопрос:

В моем частном проекте я использую boost::signals2 для отправки сообщений из нескольких классов общему получателю. Мой вопрос: как я могу отправлять сообщения из конструктора класса? Проблема в том, что сигнал в этом случае не существует до тех пор, пока не будет создан экземпляр объекта класса A (до тех пор, пока не будет выполнен конструктор). Но на данный момент еще не было возможности для какого-либо другого кода установить слот.

Я попытался использовать статический импульс::сигнал2::сигнал<void(const std::строка и Msg)>, но затем я получаю ошибки загрузчика «неопределенная ссылка на класс::сигнал».

Ниже приведена очень урезанная версия моего кода для иллюстрации. Вопрос в следующем: как класс B может получить сообщение от конструктора класса A? Или другими словами: как я могу подключить слот к сигналу класса A до выполнения конструктора класса A?

 class A { 
public:
   /*static*/ boost::signals2::signal<void(const std::string amp; Msg)> sigA;
   A() { sigA("message from constructor A"); }
};

class B { 
   B() {
      A a;
      a.sigA.connect([](const std::string amp; msg) { std::cerr << msg << 'n'; } );
   }   
};
 

Для вашей информации: я использую fedora 33, gcc 11.2.1 и C 17.

Пожалуйста, извините мой английский: это не мой родной язык, и мне не хватает некоторого опыта…

Ответ №1:

Технически, вы могли бы передать слот class A конструктору.

 class A { 
public:
   A(boost::signals2::slot<void(const std::string amp;)> slot) { 
   sigA.connect(slot);
   sigA("message from constructor A"); }
};

class B { 
   B() {
      A a([](const std::string amp; msg) { std::cerr << msg << 'n'; });
   }   
}; 
 

Обратите внимание, что семантика немного странная. На этот раз нет никакого способа получить connection объект. вы могли бы использовать параметр out в конструкторе, но это действительно запах кода.

Как правило, конструкторы используются для инициализации объекта, а не для выполнения логики, которая может повлиять на объекты, не являющиеся членами класса.

Я бы настоятельно рекомендовал подписаться на слот отдельным способом.

Комментарии:

1. Я на 100% согласен с вашими ответами. Я думаю, что я значительно упростил свой пример кода. Таким образом, исходная проблема, которую я описал в своем вопросе, может быть покрыта плохо выбранным примером. Тем временем я сам нашел решение (см. Ниже). Спасибо вам за ваш ответ

Ответ №2:

Тем временем я сам нашел решение своей проблемы. Ниже приведен полностью рабочий пример того, как конструктор класса A запускает сигнал, который сам является (статическим) членом класса A:

 #include <string>
#include <iostream>
#include <functional>
#include <boost/signals2/signal.hpp>

class A { 
public:
   using Signal = boost::signals2::signal<void(const std::string amp; Msg)>;
   static Signal sigA;

   A() { sigA("message from constructor A"); }
};

A::Signal A::sigA;

class B { 
public:
   B() {}
   void disp(const std::string amp; msg) { std::cout << msg << 'n'; }
};

int main()
{
   B b; // slot b.disp() now exists
   auto slot = std::bind(amp;B::disp, b, std::placeholders::_1);
   A::sigA.connect(slot); // subscribe slot b.disp() to A::sigA
   A a; // constructor of class A fires signal sigA, b.disp() writes to cout
};