Suppose we have a function
template<typename T, typename... Args>
T f(Args... args);
and we want to call f
in an other function
template<typename... Args>
void bar(Args... args) {
// f(args1, ..., args(i-1), "modified argsi", args(i+1), ..., argsn);
}
and modify the i
-th argument (and leave the other arguments untouched) for all i = 1, ..., n
. f
will return a result and I want to store all n
results in a valarray
.
How can we do that?
With I
a compile time value, you may do:
namespace detail
{
template<std::size_t I>
struct impl
{
template <typename TUPLE>
auto operator() (TUPLE&& t) { return std::get<I>(t); }
};
template<>
struct impl<2>
{
template <typename TUPLE>
auto operator() (TUPLE&& t) { return std::get<2>(t) + 40; }
};
template <std::size_t... Is, typename TUPLE>
void bar(std::index_sequence<Is...>, TUPLE&& Tuple) {
return f(impl<Is>{}(std::forward<TUPLE>(Tuple))...);
}
}
template<typename... Args>
void bar(Args... args) {
detail::bar(std::index_sequence_for<Args...>(), std::forward_as_tuple(args...));
}
Live Demo
With i
a runtime value:
namespace detail
{
template<class T>
auto modifier(T&& arg, std::size_t i, std::size_t pos) {
if (i == pos)
return arg + 40; // Or appropriate modification.
else
return std::forward<T>(arg);
}
template <std::size_t... Is, typename... Args>
void bar(std::size_t pos, std::index_sequence<Is...>, Args&&... args) {
return f(modifier(std::forward<Args>(args), Is, pos)...);
}
}
template<typename... Args>
void bar(std::size_t pos, Args&&... args) {
detail::bar(pos, std::index_sequence_for<Args...>(), std::forward<Args>(args)...);
}
Live Demo
Well, a lookup table does the job, if branching is to be avoided. Rough sketch:
#include <tuple>
#include <utility>
#include <iostream>
void foo(std::string a, std::string b, std::string c) {
std::cout << a << '|' << b << '|' << c;
}
template <typename, typename> struct passerAux;
template <std::size_t... prevI, std::size_t... followI>
struct passerAux<std::index_sequence<prevI...>, std::index_sequence<followI...>> {
template <typename... Args>
static decltype(auto) passer( Args&&... args ) {
auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
return foo( std::forward<std::tuple_element_t<prevI, decltype(tuple)>>(std::get<prevI>(tuple))...,
"ModifiedArg",
std::forward<std::tuple_element_t<followI+sizeof...(prevI)+1, decltype(tuple)>>(std::get<followI+sizeof...(prevI)+1>(tuple))... );
}
};
template <typename... Args, std::size_t... indices>
decltype(auto) passer( std::size_t i, std::index_sequence<indices...>, Args&&... args ) {
void(*lookup[])(Args&&...) {
passerAux<std::make_index_sequence<indices>, std::make_index_sequence<sizeof...(Args)-indices-1>>::passer...
};
return lookup[i](std::forward<Args>(args)...);
}
template <typename... Args>
decltype(auto) passer( std::size_t i, Args&&... args ) {
return passer(i, std::make_index_sequence<sizeof...(Args)>{}, std::forward<Args>(args)... );
}
int main() {
passer(0, "A", "B", "C"); std::cout << '\n';
passer(1, "A", "B", "C"); std::cout << '\n';
passer(2, "A", "B", "C");
}
Demo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With