ReactiveX / RxCpp

Reactive Extensions for C++
Apache License 2.0
3.07k stars 396 forks source link

Compile-error using tap (but not with subscribe) #472

Open thorstink opened 5 years ago

thorstink commented 5 years ago

Hi :-),

I was trying to move all side-effects in my application into taps instead of in the subscribe methods;

However, the following snippet does not compile:

typedef std::pair<int, int> dataMsg;

auto loop = rxcpp::synchronize_event_loop();
auto data = rxcpp::subjects::subject<dataMsg>();
auto dataSubscriber = data.get_observable();

auto time = rxcpp::observable<>::interval(10ms);

// create data through measurements
time 
.subscribe_on(loop)
.map([&](int v){
    return std::make_pair(v, 5*v); 
})
.tap(
    [&data](const auto& measurement){data.on_next(measurement);},
    // [](std::exception_ptr ep){printf("Tap -       OnError: %s\n", rxcpp::util::what(ep).c_str());}
)
.subscribe();

while the following does:

typedef std::pair<int, int> dataMsg;

auto loop = rxcpp::synchronize_event_loop();
auto data = rxcpp::subjects::subject<dataMsg>();
auto dataSubscriber = data.get_observable();

auto time = rxcpp::observable<>::interval(10ms);

// create data through measurements
time 
.subscribe_on(loop)
.map([&](int v){
    return std::make_pair(v, 5*v); 
})
.tap(
    [&data](const auto& measurement){data.on_next(measurement);},
    [](std::exception_ptr ep){printf("Tap -       OnError: %s\n", rxcpp::util::what(ep).c_str());}
)
.subscribe();

A part of the compile error is:

required from here
/usr/local/include/rxcpp/rx-observer.hpp:439:13: error: no matching function for call to ‘rxcpp::detail::virtual_observer<std::pair<double, double> >::on_next(std::__exception_ptr::exception_ptr)’
             destination->on_next(std::forward<V>(v));
             ^~~~~~~~~~~
/usr/local/include/rxcpp/rx-observer.hpp:353:18: note: candidate: void rxcpp::detail::virtual_observer<T>::on_next(T&) const [with T = std::pair<double, double>]
     virtual void on_next(T&) const {};
                  ^~~~~~~
/usr/local/include/rxcpp/rx-observer.hpp:353:18: note:   no known conversion for argument 1 from ‘std::__exception_ptr::exception_ptr’ to ‘std::pair<double, double>&’
/usr/local/include/rxcpp/rx-observer.hpp:354:18: note: candidate: void rxcpp::detail::virtual_observer<T>::on_next(T&&) const [with T = std::pair<double, double>]
     virtual void on_next(T&&) const {};
                  ^~~~~~~
/usr/local/include/rxcpp/rx-observer.hpp:354:18: note:   no known conversion for argument 1 from ‘std::__exception_ptr::exception_ptr’ to ‘std::pair<double, double>&&’

But it is not clear to me why this happens (if I look at the rxcpp twitter-example, I do not see the OnError explicitly defined in the tap-operators for instance..).

kirkshoop commented 5 years ago

Looks like a bug in the design of the make_observer overloads. See the overloads for DefaultOnError that are used by tap. There are multiple work arounds to disambiguate this. Specifying the error method (either as a function or the built in OnErrorIgnore), specifying the value argument type explicitly, calling make_observer directly with unambiguous args, etc..

thorstink commented 5 years ago

Avoiding the auto in the tap indeed also helps.

In an attempt to learn, I'll toy around to see if I can come up with a pr that allows auto..