Jak przechować slot zwracany przez boost:bind

Jak przechować slot zwracany przez boost:bind
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0

Cześć, sytuacja wygląda tak. Mam jakąś metodę, którą podłączam do sygnału:

Kopiuj
auto event = boost::bind(&AppManager::Impl::OnStart, this, _1);
cmdReg.OnStart.connect(event);

I później trzeba to rozłączyć:

Kopiuj
auto event = boost::bind(&AppManager::Impl::OnStart, this, _1);
cmdReg.OnStart.disconnect(event);

Aż się prosi, żeby zmienna event była składnikiem klasy. Tylko w żaden sposób nie mogę tego ogarnąć. Próbowałem to deklarować jako:

Kopiuj
boost::function<void(MyEventArgs&)> event;

Ale się wykrzacza przy budowaniu (czepia się o operator == gdzieś w boost.) Próbowałem to też deklarować jako slot. Ale wszystko na nic. Jest jakiś sposób na to?

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
2

Pokaż MRE, bo trywialny przykład jest ok https://godbolt.org/z/7Td3rb6Tz

Kopiuj
#include<iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>

struct WithBoundField
{
    WithBoundField()
    : fkn(boost::bind(&WithBoundField::method, this, _1))
    {}
    
    int method(char a)
    {
        std::cout <<"passed " << a << " to method\n";
        return 0;
    };

    boost::function<int(char)> fkn;

};


int main(int, char*[])
{
    WithBoundField x;
    x.fkn('a');
    return 0;
}

BTW, skoro używasz auto to po co boost, jak masz std::function, std::bind itd. (bo to pewnie C++11)?

edytowany 3x, ostatnio: alagner
kq
Oraz lambdy :​)
AL
@kq: takoż. ++.
JU
Wszystko się rozbija o signal connect
kq
Serio, MCVE by się przydało.
JU
Za dużo pieprzenia z tym teraz. Generalnie problem leży w connect. Bo tu się czepia, że nie mogę connectować boost::function
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
1

Bez MCVE ciężko powiedzieć, ale szklana kula każe sprawdzić, czy nie chcesz użyć std::ref albo boost::ref (o ile istnieje), bo bind robi kopię argumentów (w przeciwieństwie do np. lambdy).


AL
istnieje ;)
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
0

Tylko dalej coś się nie składa co mówisz, bo connectuje ok:
https://godbolt.org/z/KbP8Pf9Gv

edytowany 1x, ostatnio: alagner
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0

Pokazałem cały znaczący kod. Reszta:

Kopiuj
struct MyEventArgs
{
	String cmdName; //string z zewnętrznej biblioteki
	bool handled;
};

typedef boost::signals2::signal<void(MyEventArgs&)> OnStartEvent;

class ICommandRegistrator
{
public:
  OnStartEvent OnStart;
}

Później w implementacji:

Kopiuj
class CommandRegistrator: public ICommandRegistrator
{
public:
    void Start()
   {
       //Tworzę i wypełniam MyEventArgs, a potem
       OnStart(args);
   }
}

No i z drugiej strony podłączam tak, jak pokazałem wyżej.

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
0

O coś takiego Ci chodzi?

Kopiuj
class CommandRegistrator: public ICommandRegistrator
{
public:
    boost::function<void(MyEventArgs&)> bfkn;

    CommandRegistrator()
    {
        bfkn = boost::bind(boost::ref(OnStart), _1);
    }
    void Start()
   {
       MyEventArgs args{"abcd", false};
    //    OnStart(args);
        bfkn(args);
   }
};
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0

Nie, ja się pytam, jak to przechować w innej klasie. Kod z pierwszego postu pochodzi z zupełnie innej klasy, cmdReg jest obiektem CommandRegistrator

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
0

No tak samo. Funktor (a tym jest OnStart) może być "bound directly"

Kopiuj
    CommandRegistrator cmdreg;
    boost::function<void(MyEventArgs&)> boundF;
    boundF = boost::bind(boost::ref(cmdreg.OnStart), _1);
edytowany 1x, ostatnio: alagner
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
2

@Juhas Ty zakładasz, że siedzimy w twojej głowie lub widzimy twój monitor.
Musisz zdać sobie sprawę, że my nie wiemy co robisz, jaki masz kod i na czym polega twój problem, ergo musisz dostarczyć wszystkie niezbędne informacje.

To zdanie:

Juhas napisał(a):

Aż się prosi, żeby zmienna event była składnikiem klasy. Tylko w żaden sposób nie mogę tego ogarnąć. Próbowałem to deklarować jako:

Kopiuj
boost::function<void(MyEventArgs&)> event;

Ale się wykrzacza przy budowaniu (czepia się o operator == gdzieś w boost.) Próbowałem to też deklarować jako slot. Ale wszystko na nic. Jest jakiś sposób na to?

Dostarcz MCVE (minimalny kompletny weryfikowalny przykład) w którym odtwarzasz błąd z brakującym operatorem ==.
Jak nie potrafisz to wklej pełen log kompilatora (od pierwszego błędu do dołu), bo operator == gdzieś w boost to nie jest opis problemu, tylko zgłoszenie dla jasnowidza.

Coś takiego może być dobrym punktem startowym (próbowałem odtworzyć twój problem na podstawie dostarczonych danych, ale wszystko działa).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 3x, ostatnio: MarekR22
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
4

Dobra chyba mam MCVE: https://godbolt.org/z/6oEnqz36a
Po prostu jeden z argumentów, które są potrzebne dla boost::bind są nieporównywalne.
Ergo boost::bind nie jest w stanie wygenerować operatora porównania (równości).
Efekt końcowy jest taki, że próba wykonania disconnect z argumentem jest niemożliwa od wykonania, bo nie ma jak wykonać porównania na tym obiekcie przekazanym do disconnect, więc nie wiadomo, które połączenie należy zerwać.

W danych, które podałeś nie ma żadnego argumentu bind, którego nie da się porównywać. Wygląda na to, że jednak jestem jasnowidzem :).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
1

OK, tu jest dokładnie to: https://godbolt.org/z/GKMrjdfbe

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
1

std::function oraz zwrotki z bind nie implementują interfejsu ==. Musisz napisać własny wrapper na std::function oraz zaimplementować ten operator. To tak na szybko. Jak będę mieć chwilę może popróbuję wieczorem coś wymóżdżyć.

JU
Ale skąd tam w ogóle std::function, jak wszystko idzie przez boost?
MarekR22
@alagner przeczytaj komunikat kompilatora, to się okaże, że twoje rady nie mają sensu.
AL
@Juhas: sorry, z rozpędu napisałem std, chodziło oczywiście o boosta. Aczkolwiek z std na 99% będzie to samo.
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
1

No to teraz widać konkretnie w czym problem.
W twoim kodzie, kompilator narzeka, że operator porównania nie może być wybrany bo są możliwe dwie implementacje do wybrania.
Dziś nie mam czasu, żeby zrozumieć skąd dokładnie wzięła się ta dwuznaczność, nie jest to oczywiste.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
2

Problem rozwiązany tak jak należy (a nie tak jak próbuje OP): https://godbolt.org/z/E68eYWKbq

Kopiuj
class Handler
{
public:
    Handler(Source & source)
    {
        m_scoped_connection = source.OnStart.connect(boost::bind(&Handler::OnStart, this, _1));
    }

private:
  boost::signals2::scoped_connection m_scoped_connection;

  void OnStart(MyEventArgs& args)
  {
      std::cout << "Zaczelo sie...";
  }
};

I to kasując sporo kodu :).

Swoją drogą, będę jeszcze rozkminiał, czemu przykład od OP się nie kompiluje.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 4x, ostatnio: MarekR22
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
0

@MarekR22: zgaduję, :51:6: error: ambiguous overload for 'operator==' wskazuje Ci, że palnąłem głupotę odn. tego, że te typy nie są porównywalne. Jednakże spojrzyj do dokumentacji: https://www.boost.org/doc/libs/1_76_0/doc/html/function/faq.html#id-1.3.17.7.2.1

Comparison between boost::function objects cannot be implemented "well", and therefore will not be implemented.

...i dalej tłumaczą, że na skutek szczegółów implementacyjnych to się wysypie właśnie niejednoznaczności, a nie braku operatora.
Co ciekawe dalej piszą

The Signals library has a way around this.

Ciekawe czy signals2 też...

Przykład coby nie być gołosłownym:
https://godbolt.org/z/n3KvejrqW

edytowany 1x, ostatnio: alagner
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
0

Sorry za posta pod postem:
poczytałem dokładniej dokumentację boost::function i odn. operatora == (f i g to odp. lewy i prawy jego argument):

True when f stores an object of type Functor and one of the following conditions applies:
g is of type reference_wrapper<Functor> and f.target<Functor>() == g.get_pointer().
g is not of type reference_wrapper<Functor> and function_equals(*(f.target<Functor>()), g).

I wychodzi na to, że o ile samych boost::function porównać nie można, tak można porównać adresy ich bebechów, ergo można przekazać do connect/disconnect referencje (czyli tu: reference wrappery) na te funktory:

Kopiuj
class Handler
{
public:
    Handler(Source & source)
      :m_source(source)
    {
        m_event = boost::bind(&Handler::OnStart, this, _1);
        m_source.OnStart.connect(boost::ref(m_event));
        assert(!m_source.OnStart.empty());
    }

    ~Handler()
    {
        m_source.OnStart.disconnect(boost::ref(m_event));
        assert(m_source.OnStart.empty());
    }

https://godbolt.org/z/7dsfdq9dT

darkbit
  • Rejestracja:ponad 20 lat
  • Ostatnio:dzień
  • Lokalizacja:~Koszalin
1

A z wykorzystaniem boost::signals2::connection?
I trochę nazewnictwo poprawiłem ;). Bez przechowywania referencji do obiektu źródłowego, bez boost:ref.
https://godbolt.org/z/Wr73KsG9e

AL
to też jest pomysł. Ale pytanie (pewnie w dokumentacji jest odpowiedź) jak to się zachowa przy selektywnym odpinaniu slotów od sygnału.
darkbit
Jeśli dobrze rozumiem dokumentację to boost::signals2::connection jest 1-1.
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 4 godziny
0

Miałem to kiedyś fajnie zrobione na pierwszych signalsach, i z tego co pamiętam signals2 wszystko utrudniały.
A teraz signals 1 już są chyba usunięte z nowych wersji Boosta :(

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)