"Unpacking" a Tuple to Call a Matching Function Pointer

unpacking a tuple to call a matching function pointer

The C++17 solution is simply to use std::apply:

auto f = [](int a, double b, std::string c) { std::cout<<a<<" "<<b<<" "<<c<< std::endl; };
auto params = std::make_tuple(1,2.0,"Hello");
std::apply(f, params);

Just felt that should be stated once in an answer in this thread (after it already appeared in one of the comments).


The basic C++14 solution is still missing in this thread. EDIT: No, it's actually there in the answer of Walter.

This function is given:

void f(int a, double b, void* c)
{
std::cout << a << ":" << b << ":" << c << std::endl;
}

Call it with the following snippet:

template<typename Function, typename Tuple, size_t ... I>
auto call(Function f, Tuple t, std::index_sequence<I ...>)
{
return f(std::get<I>(t) ...);
}

template<typename Function, typename Tuple>
auto call(Function f, Tuple t)
{
static constexpr auto size = std::tuple_size<Tuple>::value;
return call(f, t, std::make_index_sequence<size>{});
}

Example:

int main()
{
std::tuple<int, double, int*> t;
//or std::array<int, 3> t;
//or std::pair<int, double> t;
call(f, t);
}

DEMO

Unpacking arguments from tuples

I think that @Xeo's comment summed it up well. From 14.5.3 of the C++11 standard:

A pack expansion consists of a pattern and an ellipsis, the
instantiation of which produces zero or more instantiations of the
pattern in a list.

In your case, by the time you finish with the recursive template instantiation and end up in the partial specialization, you have

f(std::get<N>(std::forward<Tuple>(t))...);

...where N is parameter pack of four ints (0, 1, 2, and 3). From the standardese above, the pattern here is

std::get<N>(std::forward<Tuple>(t))

The application of the ... ellipsis to the above pattern causes it to be expanded into four instantiations in list form, i.e.

f(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));

Unpacking a range of tuples into n-ary function

It sounds like what you actually need is a function adaptor that explodes tuple arguments. Something like this (LIVE):

#include <type_traits>
#include <utility>
#include <range/v3/core.hpp>
#include <range/v3/utility/semiregular.hpp>
#include <range/v3/utility/tuple_algorithm.hpp>

template<class F>
struct decomposed_fn
{
private:
CONCEPT_ASSERT(ranges::CopyConstructible<F>());
ranges::semiregular_t<F> f_;

template<class FF>
struct caller
{
FF &f_;

template<class... Args>
RANGES_CXX14_CONSTEXPR auto operator()(Args &&...args)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
ranges::invoke(f_, std::forward<Args>(args)...)
)
};

public:
decomposed_fn() = default;
RANGES_CXX14_CONSTEXPR explicit decomposed_fn(F f)
noexcept(std::is_nothrow_move_constructible<F>::value)
: f_(std::move(f))
{}

template<class T>
RANGES_CXX14_CONSTEXPR auto operator()(T &&t)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
ranges::tuple_apply(caller<F>{f_}, std::forward<T>(t))
)

template<class T>
RANGES_CXX14_CONSTEXPR auto operator()(T &&t) const
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
ranges::tuple_apply(caller<F const>{f_}, std::forward<T>(t))
)
};

template<class F,
CONCEPT_REQUIRES_(ranges::CopyConstructible<std::decay_t<F>>())>
RANGES_CXX14_CONSTEXPR auto decomposed(F &&f)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
decomposed_fn<std::decay_t<F>>(std::forward<F>(f))
)

with which you could formulate your range as:

auto chars = view::zip(r1, r2)
| view::transform(decomposed([](int, char x) { return x; }));

Variadic template returning a N-tuple based on an unknown number of arguments

That's heavy pseudocode, I'll answer with heavy pseudocode:

template<typename ... Ts>
constexpr auto fill_and_gen_objects(Ts* ... os)
{
bool some_status = true; //whatever
return std::make_tuple(some_status, gen_object(os) ...);
}

Ok, actually it even compiles, see here

EDIT: downgraded to C++14 ... that's what you've tagged.


Same for C++17 using CTAD

template<typename ... Ts>
constexpr auto fill_and_gen_objects(Ts* ... os)
{
bool some_status = true; //whatever
return std::tuple{some_status, gen_object(os) ...};
}

Same for C++20 using abbreviated function template syntax

constexpr auto fill_and_gen_objects(auto* ... os)
{
bool some_status = true; //whatever
return std::tuple{some_status, gen_object(os) ...};
}

C++20 with indices by using integer sequence (untested):

constexpr auto fill_and_gen_objects(auto* ... os)
{
bool some_status = true; //whatever
return []<int ... I>(std::index_sequence<I...>, auto tup){ return std::tuple{some_status, gen_object(std::get<I>(tup)) ...};}
(std::make_index_sequence<sizeof...(os)>{}, std::tuple{os...})
}

Furthermore, here is the C++27 solution:

void do_my_fckng_work() { bool asap = true; }


Related Topics



Leave a reply



Submit