Any Solution to Unpack a Vector to Function Arguments in C++

Any Solution to Unpack a Vector to Function Arguments in C++?

You can use a pack of indices:

template <size_t num_args>
struct unpack_caller
{
private:
template <typename FuncType, size_t... I>
void call(FuncType &f, std::vector<int> &args, indices<I...>){
f(args[I]...);
}

public:
template <typename FuncType>
void operator () (FuncType &f, std::vector<int> &args){
assert(args.size() == num_args); // just to be sure
call(f, args, BuildIndices<num_args>{});
}
};

There's no way to remove the need to specify the size in the template though, because the size of a vector is a runtime construct, and we need the size at compile-time.

Unpack vector into arguments to call functions that have a variable number of arguments

First, here's funcPointer which returns a lambda doing the std::vector-to-arguments juggling before calling a given function, generated based on the function's arity:

template <class F, std::size_t... ParamsIdx>
auto funcPointer(F f, std::index_sequence<ParamsIdx...>) {
return [f](std::vector<std::string> const &args) {
assert(args.size() == sizeof...(ParamsIdx));
return f(args[ParamsIdx]...);
};
}

template <class... Params>
auto funcPointer(int (*f)(Params...)) {
return funcPointer(f, std::index_sequence_for<Params...>{});
}

These lambdas can then be stored together in a std::map<int, std::function<int(std::vector<std::string> const &)>>:

std::map<int, std::function<int(std::vector<std::string> const &)>> map = {
{1, funcPointer(my_functionA)},
{2, funcPointer(my_functionB)}
};

Finally, the call is straightforward:

void some_useful_function(std::vector<std::string> vec, int choice) {
if (map.count(choice) > 0) {
int val = map[choice](vec);
// Do stuff with the return value
std::cout << "Call succeeded, got " << val << '\n';
}
}

See it live on Wandbox

Unpack an array of arguments for a function call

You can just forward the arguments, without using arrays, or use tuples like std::apply().

#include <vector>

class MyClass {};

void testA(int, float, const char* ) {}
void testB(int, float, double ) {}
void testC(MyClass, float, double ) {}

template <class T, typename... Args>
void applyA(T&& foo, Args... args)
{
foo(args...);
}

template <class T, typename... Args>
void applyB(T&& foo, Args... args)
{
MyClass cls;
foo(cls, args...);
}

int main()
{
applyA(testA, 5, 0.5f, "abc");
applyA(testB, 5, 0.5f, 1.5);
applyB(testC, 0.5f, 1.5);

return 0;
}

Example with std::apply() c++17

#include <tuple>

...
std::apply(testA, std::make_tuple(5, 0.5f, "abc"));
std::apply(testB, std::make_tuple(5, 0.5f, 1.5));
std::apply(testC, std::make_tuple(MyClass{}, 0.5f, 1.5));

Example with self-made apply () c++11

With help from "unpacking" a tuple to call a matching function pointer SO question's answer.

template<int ...>
struct seq { };

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};

template<typename F, typename Tuple, int... S>
void my_apply_impl(F&& func, Tuple&& params, seq<S...> ) {
func(std::get<S>(std::forward<Tuple>(params)) ...);
}

template<typename F, typename Tuple>
void my_apply(F&& func, Tuple&& params) {
my_apply_impl(std::forward<F>(func), std::forward<Tuple>(params), typename gens<std::tuple_size<Tuple>::value>::type() );
}

...
my_apply(testA, std::make_tuple(5, 0.5f, "abc"));
my_apply(testB, std::make_tuple(5, 0.5f, 1.5));
my_apply(testC, std::make_tuple(MyClass{}, 0.5f, 1.5));

Demo

Unpack vector into function arguments

Building upon the hint by Roland, a possible implementation of fixVector is

fixVector <- function( f, vec ) {
function( args ) {
do.call( f, c( list( vec ), as.list( args ) ) )
}
}

Usage example:

fun <- function( x, a, b, c ) {
sin( x * a ) * exp( -x * b ) + x * c
}

fx <- fixVector( fun, 1:10 )
fx( 1:3 )
# [1] 3.113881 6.016654 9.000350 11.999746 14.999956 17.999998 21.000001
# [8] 24.000000 27.000000 30.000000

Unpack vector to variables in C

You need to assign values to each of the variables separately. You of course can write some specific function/macro do this task, but it's not worth it.

Expand std::vector into parameter pack

It's possible, as long as you provide an upper bound to the number of arguments.

Using Xeo's implementation of std::index_sequence for C++11:

template <unsigned... Idx>
void trampoline(const std::vector<int>& vElements, seq<Idx...>) {
return DoStuff(vElements[Idx]...);
}

template <std::size_t Arity>
void trampoline(const std::vector<int>& vElements) {
return trampoline(vElements, typename gen_seq<Arity>::seq{});
}

template <unsigned... Idx>
void CallDoStuff(const std::vector<int>& vElements, seq<Idx...>) {
using trampoline_t = void (*)(const std::vector<int>&);
constexpr trampoline_t trampolines[]{
trampoline<Idx>...
};
trampolines[vElements.size()](vElements);
}

template <std::size_t Max>
void CallDoStuff(const std::vector<int>& vElements) {
assert(vElements.size() <= Max);
return CallDoStuff(vElements, typename gen_seq<Max + 1>::seq{});
}

See it live on Wandbox

How do I get multiple values unpacked in C++ vectors

If you have a function

std::vector<cv::Vec3b> colors = find_dominant_colors(matImage, count);

and now you want to change the function to return "more", then you can declare a data structure

struct find_dominant_colors_result {
std::vector<cv::Vec3b> colors;
cv::Mat quantized;
cv::Mat viewable;
cv::Mat dom;
};

Now the call would look like this:

find_dominant_colors_result x = find_dominant_colors(matImage, count);

or rather

auto x = find_dominant_colors(matImage, count);

while you would have to modify the function to

find_dominant_colors_result find_dominant_colors(cv::Mat img, int count) {
find_dominant_color_result result;
const int width = img.cols;
const int height = img.rows;
result.colors = get_dominant_colors(root);

result.quantized = get_quantized_image(classes, root);
result.viewable = get_viewable_image(classes);
result.dom = get_dominant_palette(result.colors);

cv::imwrite("./classification.png", result.viewable);
cv::imwrite("./quantized.png", result.quantized);
cv::imwrite("./palette.png", result.dom);

return result;
}

Strange error when applying arguments from a vector to a function using variadic templates

You can't use std::result_of<FuncType>::type, you would need to add the arguments, e.g. std::result_of<FuncType(int,int)>::type. In your case, this is a more difficult than the alternative, hence I suggest you use:

template <size_t num_args>
struct unpack_caller
{
private:
template <typename FuncType, size_t... I>
auto call(FuncType &f, std::vector<int> &args, indices<I...>)
-> decltype( f(args[I]...) )
{
return f(args[I]...);
}

public:
template <typename FuncType>
auto operator () (FuncType &f, std::vector<int> &args)
-> decltype( std::declval<unpack_caller<num_args>>().call(f, args, BuildIndices<num_args>{}) )
{
return call(f, args, BuildIndices<num_args>{});
}
};

Live example

Note that with C++14, you could leave out the -> decltype(...) part and simply rely on auto alone.



Related Topics



Leave a reply



Submit