The thing I am trying to achieve is as follows, together with where i am right now:
template <typename Fn, typename Tuple, size_t... Is>
auto apply_if_impl(Tuple t, Fn&& f, std::index_sequence<Is...>) {
return std::make_tuple(
std::is_same_v<std::string, std::tuple_element_t<Is, Tuple>> ?
f(std::get<Is>(t)) :
std::get<Is>(t)...
);
}
template <typename Fn, typename ...Ts>
auto apply_if(std::tuple<Ts...> t, Fn&& f) {
return apply_if_impl(t, f, std::make_index_sequence<sizeof...(Ts)>());
}
and implement this in a way that, for example:
int main() {
std::tuple<int, std::string, float> t{42, "hello", 3.14f};
// this one should return
// std::tuple<int, std::size_t, float>{42, 5, 3.14f};
apply_if(t, [](std::string s){ return s.size(); });
// return value of this should be equal to t above since
// there is no vector element in the given tuple
apply_if(t, [](std::vector<int> s){ return s.size(); });
}
will return another std::tuple
but an std::tuple<int, std::size_t, float>
with elements 42 and 5 (length of "hello"
) and 3.14. If there is no element in the given tuple that is feasible to apply the given callable, just return the given tuple without doing anything. So, a copy of given std::tuple<int, std::string, float>
will be returned in this latter case, or moved, whatever.
The problem I have is that compiler still sees the function being applied to other members in the tuple, in the ternary statement I have. How can I go around this? I need a compile-time ternary thing that would expand that make_tuple
call correctly. Lastly, I need to get rid of that hardcoded std::string
as well. I need to put in the argument type of callable there.
EDIT: Don't hesitate to use libraries like boost::hana
if they are going to make the solution easier. Would be a nice exercise for me as well.
You can go via another intermediate template:
template <bool>
class Select
{
public:
template <typename F, typename T>
T& operator()(F&, T& t) const
{
return t;
}
};
template <>
class Select<true>
{
public:
template <typename F, typename T>
auto operator()(F& f, T& t) const -> decltype(f(t))
{
return f(t);
}
};
template<typename Fn, typename Tuple, size_t ... Is>
auto apply_if_impl(Tuple t, Fn&& f, std::index_sequence<Is...>)
{
return std::make_tuple
(
Select<std::is_same_v<std::string, std::tuple_element_t<Is, Tuple>>>()
(f, std::get<Is>(t))...
);
}