In the following code:
#include <iostream>
#include <utility>
#include <set>
template <typename... Args>
void f(Args... args) {
std::cout << sizeof...(Args) << " elements.\n";
}
template <std::size_t... Is>
void g (std::index_sequence<Is...>, const std::set<int>& set) {
f((set.find(Is) == set.end() ? Is : 2*Is)...);
}
int main() {
g (std::make_index_sequence<10>{}, {1,3,7,8});
}
I want f((set.find(Is) == set.end() ? Is : 2*Is)...);
to use Is
if set.find(Is) == set.end()
but NOTHING otherwise (instead of 2*Is
). Thus the number of arguments passed is not fixed. How to achieve that?
Edit: Sorry, but I simplified the problem too much. The code below reflects more the true problem:
#include <iostream>
#include <utility>
#include <tuple>
template <typename... Args>
void f(Args... args) {
std::cout << sizeof...(Args) << " elements.\n";
}
struct NullObject {};
template <typename Tuple, std::size_t... Is>
void g (std::index_sequence<Is...>, const Tuple& tuple) {
f ((std::get<Is>(tuple) != std::get<Is+1>(tuple) ? std::get<Is>(tuple) : NullObject{})...);
}
int main() {
g (std::make_index_sequence<8>{}, std::make_tuple(2,1.5,'a','a',true,5,5,false));
}
The above does not compile because of mixed types passed by the ternary operator, but I think you can see my idea here. I want to pass NOTHING if the condition std::get<Is>(tuple) != std::get<Is+1>(tuple)
, so instead I pass NullObject{}
and then somehow try to remove all NullObjects from the arguments of f
to get the true arguments passed to f
.
You can't use a ternary operator for this - that requires two expressions that have a common type. No dice here. I know of no way of conditionally returning a different type based on a runtime comparison.
You'd have to conditionally forward the type to a different function, by way of just introducing another helper function that builds up the Args...
and a simple if
statement:
template <size_t... Js>
void fhelper (std::index_sequence<>, const std::set<int>& , std::index_sequence<Js...>) {
f(Js...);
}
template <std::size_t I, size_t... Is, size_t... Js>
void fhelper (std::index_sequence<I, Is...>, const std::set<int>& set, std::index_sequence<Js...>) {
if (set.find(I) == set.end()) {
fhelper(std::index_sequence<Is...>{}, set, std::index_sequence<Js..., I>{});
}
else {
fhelper(std::index_sequence<Is...>{}, set, std::index_sequence<Js...>{});
}
}
int main() {
fhelper (std::make_index_sequence<10>{}, {1,3,7,8}, std::index_sequence<>{});
}