Я делаю грубую и упрощенную имитацию подключения сигнала Qt и хочу реализовать API, например:
class MyEvent;
class MyObject;
static void connect( MyObject* sender,
std::string eventName,
MyObject* listener,
SomeCallable listenerMethod );
А вот черты для SomeCallable
:
MyObject
или его подклассов;const MyEvent&
и ничего не возвращает.Как я мог написать std::function
для этого? Или это возможно только с помощью std::function
?
В крайнем случае, я все еще могу использовать std::function<void(const MyEvent&)>
как SomeCallable
и позволить пользователям API сделать привязку:
struct HisListener: public MyObject
{
void foo( const MyEvent& );
};
connect( some_sender, "some_event", some_listener, std::bind(&HisListener::foo, some_listener, std::place_holders::_1) );
Но такой подход не выражает никакой связи между listener
и listenerMethod
, и я пытаюсь сделать его более ограниченным.
Отвечает ли это на ваш вопрос? Хороший способ создать шаблон проектирования наблюдателя на C++
@ ÖöTiib Я знаю упомянутый вами шаблон, но я не хочу его использовать, так как хочу, чтобы методы обратного вызова имели произвольное имя.
@Vorac Я использую здесь необработанные указатели, поскольку они не будут владеть друг другом. Соединение будет автоматически уничтожено при уничтожении отправителя или получателя.
Программирование @jiandingzhe все еще ближе к религии, чем к науке, поэтому: никогда не используйте указатели C. Весь код пишется для людей после Вас, а не для процессора. И наконец сказать что-то полезное.
@Vorac Я принадлежу к ереси C++, согласно которой необработанные указатели хороши для представления не принадлежащих, копируемых ссылок, поскольку я не использую новейший C++ 20 и нет raw_pointer
. Корректность поведения ОБЕСПЕЧИВАЕТСЯ в деструкторе MyObject.
<upvote> на Ваш вопрос. Я категорически с Вами не согласен, но уважаю Вас за утверждение неопровержимых истин.
@Vorac std::weak_ptr
требует, чтобы указатель принадлежал std::shared_ptr
. Что вы делаете с экземплярами в автоматическом хранилище?
@jiandingzhe Если вы посмотрите на код ответа на вопрос (а не на вопрос), то add_listener принимает там произвольные безымянные лямбда-выражения.
Я бы написал шаблон для привязки пользователя
static void connect( MyObject* sender,
std::string eventName,
MyObject* listener,
std::function<void(const MyEvent&)> listenerMethod );
template <std::derived_from<MyObject> Receiver>
static void connect( MyObject* sender,
std::string eventName,
Receiver* listener,
void (Receiver::*listenerMethod)(const MyEvent&) )
{
connect(sender, eventName, listener, std::bind_front(listenerMethod, listener));
}
Предложения: 1. избегать указателей в стиле C 2. упоминать имя реализуемого шаблона проектирования (наблюдатель) 3. упоминать почему/для чего.