Search code examples
c++system.reactivereactivexrxcpp

ReactiveX (rx) - Apply observable on object rather than creating object inside observable


so I've tried to comprehend ReactiveX as a library for some time now and I believe I'm starting to get the hang of the fundamentals, however, there is one problem I have which I can't find a solution to in the docs...

tldr: I want to either connect an observable to a class without actually creating the class inside the observable lambda or, create the class inside the observable but then be able to extract the class. In the end all I want to to is in some way or form make an observable of a class and then be able to use the class outside the scope of the observable.

Situation: I have three layers of classes, I have class A, B, and C, where A holds in all Bs and later all Bs, holds in multiple Cs. Both classes B and C may exist in multiple instances (A is always only one instance).

Problem: So in my application, class A will create an instance of C, and make it observable using Rx. When C is instantiated and ready I want to take the class and pass it to one of the B instances. However, my problem is that since I need to create the C class in a lambda in the observable create method I can't actually do anything with the new C Class, it only exists in the lambda scope. So what I want to do is either pass in a reference of C to the observable and give it the subscriber or somehow return the C instance out from the observable lambda. I tried giving the lambda a pointer to my class and make the lambda mutable but when doing that rx gave me compile errors and complained about the Rx method being const.

    const auto test = rx::observable<>::create<something>([&](rx::subscriber<something> subscriber) {
        C c(subscriber);
    });
    // Here I want to access c

I tried passing it in like this but with no success

    class C {
        C(rx::subscriber<someting> subscriber) {
            subscriber.on_next(55);
        }
    };

    C* c = nullptr;
    const auto test = rx::observable<>::create<something>([cLambda = c](rx::subscriber<something> subscriber) mutable {
        cLambda = new C(subscriber);
    });

    test.subscribe([](something input) {
        std::cout << "Called " << input<< std::endl;
    });
    // Compile error: C3848: expression having type 'const main::<lambda_d3f00...>' would lose some const-volatile qualifiers in order to call 'void main::<lambda_d3f00...>::operator ()(rxcpp::subscriber<something,rxcpp::observer<T,void,void,void,void>>)'
    // with
    // [
    //     T=container
    // ]

Do any other methods exist to accomplish what I want or have I just misunderstood the concept of something here?


Solution

  • Okay I solved it after a couple of days

    Turns out that I used the wrong type. From my understanding, it seems like the observable type is in fact limited to only run a method inside and not distribute the subscriber anywhere else. However, after further reading in the documentation, I found the type rx::subjects::subject<T> which is exactly what I want. A subject can generate multiple observables and subscribers as needed this making it possible to get a subscriber and pass it to the C class.

    Here is the working code:

    rx::subjects::subject<something> cSubject;
    auto subscriber = cSubject.get_subscriber();
    auto observable = cSubject.get_observable();
    
    // Give C an Emiter/subscriber
    C* c = new C(&subscriber);
    
    // Listener
    observable.subscribe([](something var) {
        std::cout << "I was called!!!" << std::endl;
    });
    
    // Now I can call c.doStuff() and trigger the listener from there