简体   繁体   中英

c++ pass content of a vector as parameters to a function

In python we can do something like this:

def test(a, b, c):
    return a+b+c

x = [1, 2, 3]
y = test(*x)

Can we do something similar to this in C++?

The solutions proposed so far are based on a run-time iteration over function arguments, which incurs some cost. They also assume argument types are the same. If the number of arguments is known at compile time (it usually is), then a different solution would be like

template <typename F, typename T>
auto tuple_call3(F&& f, const T& t)
-> decltype(std::forward<F>(f)(std::get<0>(t), std::get<1>(t), std::get<2>(t)))
   { return std::forward<F>(f)(std::get<0>(t), std::get<1>(t), std::get<2>(t)); }

struct test
{
   template <typename A, typename B, typename C>
   auto operator()(const A& a, const B& b, const C& c)
   -> decltype(a + b + c)
      { return a + b + c; }
};

int main()
{
    auto x = std::make_tuple(1, 2, 3);
    auto y = tuple_call3(test(), x);
    cout << y << endl;
}

which has no run-time cost and works with heterogeneous argument types. I have no time to further develop this now, but to make it fully generic we'd need to

  • Use universal references (like F&& ) and forwarding (like std::forward<F>(f) ) everywhere, including function arguments of course.

  • Make tuple_call variadic. For this, if L is the size of the tuple (via tuple_size ), we would need to generate sequence 0,...,L-1 at compile time (see eg function range here ). If N... is this sequence, use std::get<N>(t)... .

  • Make it work with plain functions. Now test is a function object, and could be a lambda as well, but a plain function should either not be a template, or have its template arguments explicitly specified (upon tuple_call ); otherwise its type F can't be deduced.

It would be great if all this were integrated in the C++ language but it is not (yet). At least there tools to make something roughly equivalent. By the way, I don't know what is the run-time cost of the equivalent in Python.

At least, I think below code is close to your python code

int test(const std::vector<int>& v)
{
    return std::accumulate(v.begin(), v.end(), 0);
}

std::vector<int> x = { 1, 2, 3 };
int y = test(x); 

Yes you can. For example

#include <numeric>
#include <initializer_list>

int test( std::initializer_list<int> l )
{
    return std::accumulate( l.begin(), l.end(), 0 );
}

int y = test( { 1, 2, 3 } );

Or

int test( const int a[] )
{
    return a[0] + a[1] + a[2];
}

int a[] = { 1, 2, 3 };
int y = test( a );

Or

#include <vector>
#include <numeric>
int test( const std::vector<int> &v )
{
    return std::accumulate( v.begin(), v.end(), 0 );
    // or return v[0] + v[1] + v[2];
}

std::vector<int> v = { 1, 2, 3 };
int y = test( v );

No, there is no one-liner that transforms a container to the required parameters of a function. This is due to the fact in C++ that function calls are handled during compile time while content of containers are known at runtime.

So my closest example would be

int test(int a, int b, int c) { return a + b + c; }

std::vector<int> x = { 1, 2, 3 };
int y = test(x[0], x[1], x[2]);

Mind you that since you have to take care in python that the number of elements in the container match with the expected arguments, the given example is not very usable.

Yes, if you are talking just about transforming a literal to a vector-like object, see std::initializer_list (C++11)

template <typename T>
void test(std::initializer_list<T> aList) {
    //do stuff with aList, for example std::accumulate,
    //or make a vector with it: std::vector<T> v(aList);
}

auto x = {10, 11, 12};
test(x)

but if you need to use a function which have "normal" parameters, you need to jiggle with va_args, see example in va_arg , so the answer probably would be "No".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM