I have a function transform
that takes a tuple tp
and some number of functions funcs
as arguments, two indices Begin
and End
as template arguments. The function transform
applies each of those functions from funcs
to elements of tuple tp
from std::get<Begin>(tp)
upto (but not including) std::get<End>(tp)
and collect the results into a result tuple and returns the tuple. Here is my code.
template <typename ... Rs, typename ... Ts, typename ... Fn, size_t ... Idx, size_t ... Left_Idx>
std::tuple<Rs ...> tranform_helper(std::index_sequence<Idx ...>, std::index_sequence<Left_Idx ...>,
const std::tuple<Ts ...>& tp, Fn&& ... funcs) {
return std::make_tuple<Rs ...>(std::forward<Fn>(funcs)(std::get<Idx>(tp)) ...,
std::remove_reference_t<std::tuple_element_t<Left_Idx, std::tuple<Ts ...>>>(std::get<Left_Idx>(tp)) ...);
};
template <
typename ... Rs,
typename ... Ts,
typename ... Fn,
size_t Begin = 0,
size_t End = std::index_sequence_for<Ts ...>().size()
>
std::tuple<Rs ...> transform(const std::tuple<Ts ...>& tp, Fn&& ... funcs) {
constexpr size_t func_app_iters = std::min(End - Begin, std::index_sequence_for<Fn ...>().size());
auto seq_idx = make_index_range<Begin, Begin + func_app_iters>();
auto left_idx = make_index_range<Begin + func_app_iters, End>();
return tranform_helper<Rs ...>(seq_idx, left_idx, tp, std::forward<Fn>(funcs) ...);
};
As far as I understand, only the trailing template parameters can be deduced. Since, in this function, the parameter Ts
and Fn
are always supposed to be deduced by the compiler, they must be put in the back. However, the parameter End
has a default value depending on the parameter Ts
and must be put after Ts
, which would be problematic if I need to call transform
with a specified value for End
.
My question is: Is there any way to do template argument deduction in a way that is not sensitive to the order? If not, then is it possible to specify a template parameter with default value while making the compiler to deduce some parameters before that. That is:
auto record = std::make_tuple(102, "alice", 2000, false);
auto x = transform<int, std::string, int, bool, /*something like "Begin = 1, End = 3" */ >
(record,
[](const char* name) {
std::string cp(name);
cp[0] = static_cast<char>(toupper(cp[0]));
return cp;
}
[](const int& age) {
return (age < 0 || age > 100) ? -1 : age;
}
);
std::cout << record << std::endl; // (102, "Alice", -1, false)
P.S. the actual implementation is a bit wrong in that it's only returning the elements between Begin
and End
but even I fix that, the ordering of the template parameter is still problematic.