From RxBinding<T>::Ptr T can't be deduced, as it's a non-deduced context because of nested types (see example 1) under Non-deduced contexts on cppreference and godbolt example), so the original example shouldn't have worked with argument deduction. With that in mind having typename RxBinding<Ts>::Ptr ...args will work the same way as it did before (note the syntax having ... before the argument name). I changed the variadic type template to Ts instead of T, to better represent that it's variadic.
With auto binding = makeValueBinding(std::make_tuple( /* what do do here with args ?? */ )); you can use a pack expansion with the pattern args->Get(), so the final line will be
auto binding = makeValueBinding(std::make_tuple(args->Get()...));.
Creation of the variables s0, s1, and so on is not trivial, so I'll get back to it at the end.
To make the final subscribtion, you will need to use a helper function to expand the tuple:
template<typename ...ArgTypes, typename ...Ts, std::size_t ...Ns>
void FinalSubscribeHelper(
std::tuple<ArgTypes...> const &args,
std::tuple<Ts...> const &t,
std::index_sequence<Ns...>
)
{
// using C++17's fold expressions (https://en.cppreference.com/w/cpp/language/fold)
((std::get<Ns>(args)->Update(std::get<Ns>(t))), ...); // we use the comma operator for expansion
return;
// using array initializers for C++11
using ArrayT = int[sizeof...(ArgTypes)];
ArrayT{
((
std::get<Ns>(args)->Update(std::get<Ns>(t)) // this is the pattern
), 0)...
};
return;
}
So the final subscribtion is
auto sN = binding->Subscribe([=](std::tuple<Ts...> const &t){
// Update the N bindings.
FinalSubscribeHelper(std::make_tuple(args...), t, std::make_index_sequence<sizeof...(Ts)>{});
});
For adding all subscriptions to the cleanup you will need another helper function:
template<typename BindingT, typename ...STs, typename SNT, std::size_t ...Ns>
void CleanupHelper(
BindingT const &binding,
std::tuple<Ts...> const &s,
SNT const &sN
std::index_sequence<Ns...>
)
{
// using C++17's fold expressions (https://en.cppreference.com/w/cpp/language/fold)
(binding->CleanupWith << ... << std::get<Ns>(s)) << sN;
return;
// using array initializers for C++11
/*
this only works if
binding->CleanupWith << s0 << s1 << sN;
is equivalent to
binding->CleanupWith << s0;
binding->CleanupWith << s1;
binding->CleanupWith << sN;
*/
using ArrayT = int[sizeof...(ArgTypes)];
ArrayT{
((
binding->CleanupWith << std::get<Ns>(s)
), 0)...
};
binding->CleanupWith << sN;
return;
}
So the final cleanup is
CleanupHelper(binding, s, sN, std::make_index_sequence<sizeof...(Ts)>{});.
Now get back to creating s. To create the callback I assume you want Update to be called as
b->Update(std::make_tuple(/* bM->Get() with M = 0, 1, 2, ..., I-1 */, vI, /* bM->Get() with M = I+1, I+2, ..., N-1 */));. For this you need two index sequences, one from 0 to I-1 and one from I+1 to N-1. For that let's create some type aliases to make the needed std::index_sequence's.
template<std::size_t Offset, typename T>
struct AddOffset;
template<std::size_t Offset, std::size_t ...Ns>
struct AddOffset<Offset, std::index_sequence<Ns...>>
{
using type = std::index_sequence<(Ns + Offset)...>;
};
template<std::size_t Offset, typename T>
using AddOffsetT = typename AddOffset<Offset, T>::type;
// this creates a std::index_sequence with the values
// Start, Start+1, Start+2, ..., End-1
template<std::size_t Start, std::size_t End>
using MakeIndexSequenceInRange = AddOffsetT<Start, std::make_index_sequence<End - Start>>;
To create s you will need a few helper functions:
template<typename BindingT, typename ...ArgTypes, typename VT, std::size_t ...Ns, std::size_t ...Ms>
void SubscribeCallbackHelper(
BindingT const &b,
std::tuple<ArgTypes...> const &args,
VT const &v,
std::index_sequence<Ns...>,
std::index_sequence<Ms...>
)
{
b->Update(std::make_tuple(std::get<Ns>(args)->Get()..., v, std::get<Ms>(args)->Get()...));
}
template<typename BindingWeakT, typename ...ArgTypes, std::size_t ...Ns>
auto CreateS(
BindingWeakT const &bindingWeak,
std::tuple<ArgTypes...> const &args,
std::index_sequence<Ns...>
) -> decltype(std::make_tuple(std::get<Ns>(args)->Subscribe(std::declval<void(*)(ArgTypes const &)>())...))
// I'm not sure this decltype will work, if you have C++14 you should be able to just use auto as a return type
{
return std::make_tuple(
std::get<Ns>(args)->Subscribe([bindingWeak, args](ArgTypes const &v) {
auto b = bindingWeak.lock();
if (b)
SubscribeCallbackHelper(b, args, v, MakeIndexSequenceInRange<0, Ns>{}, MakeIndexSequenceInRange<Ns+1, sizeof...(ArgTypes)>{});
})
);
}
So the creation of s will be
auto s = CreateS(bindingWeak, std::make_tuple(args...), std::make_index_sequence<sizeof...(Ts)>{});