Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I create a function which takes any number of arguments of the same type?

Tags:

c++

So basically, I want to create a function like this:

total_sum(1, 2, 5, 4, 2) // return 14
total_sum(5, 6, 2) // return 13

One way that I can use is ellipsis, something like this:

#include <cstdarg>
int total_sum(int count, ...)
{
    int sum{0};
    va_list list;
    va_start(list, count);
    for (int arg{0}; arg < count; ++arg)
    {
         sum += va_arg(list, int);
    }
    va_end(list);
    return sum;
}

But when I call total_sum(), I have to provide an extra argument. So in the example, I have to call:

total_sum(5, 1, 2, 5, 4, 2);
total_sum(3, 5, 6, 2);

which I don't really like. Also, ellipsis is really prone to error, so I want to stay away from them.

Another way I can think of is using some container:

#include <vector>
int total_sum(std::vector<int> values)
{
    int sum{0};
    for(const auto &i : values)
    {
       sum += i;
    }
    return sum;
}

and I call it like:

total_sum({1, 2, 5, 4, 2});
total_sum({3, 5, 6, 2});

But, I want to not have those curly braces, so what can I do? Is there some C++ feature that allows me to do this?


Some relevant links: restrict variadic template arguments, fold expression, parameter packs and a C++11 "equivalent" of fold expressions

like image 265
justANewb stands with Ukraine Avatar asked Nov 18 '21 03:11

justANewb stands with Ukraine


People also ask

Can functions accept any number of arguments?

When you call a function in JavaScript, you can pass in any number of arguments, regardless of what the function declaration specifies. There is no function parameter limit. In the above function, if we pass any number of arguments, the result is always the same because it will take the first two parameters only.

How do you make a function accept any number of arguments in Python?

To make a function that accepts any number of arguments, you can use the * operator and then some variable name when defining your function's arguments. This lets Python know that when that function is called with any position arguments, they should all be captured into a tuple (which that variable will point to).

Can a Python function take unlimited number of arguments?

Yes. You can use *args as a non-keyword argument. You will then be able to pass any number of arguments. As you can see, Python will unpack the arguments as a single tuple with all the arguments.

How many arguments is too many for a function?

Functions with three arguments (triadic function) should be avoided if possible. More than three arguments (polyadic function) are only for very specific cases and then shouldn't be used anyway.


Video Answer


3 Answers

Use C++17 fold expression:

template<class... Args>
constexpr auto total_sum(const Args&... args) {
  return (args + ... + 0);
}

static_assert(total_sum(1, 2, 5, 4, 2) == 14);
static_assert(total_sum(3, 5, 6, 2) == 16);
like image 106
康桓瑋 Avatar answered Oct 25 '22 08:10

康桓瑋


In C++11 and newer you can use template parameter packs to create a recursive implementation, like this:

#include <iostream>

// base function
int total_sum()
{
    return 0;
}

// recursive variadic function
template<typename T, typename... Targs>
int total_sum(T firstValue, Targs... Fargs)
{
    return firstValue + total_sum(Fargs...);
}

int main(int, char **)
{
   int s = total_sum(1, 5, 10, 20);
   std::cout << "sum is:  " << s << std::endl;
   return 0;
}

Running the above program produces this output:

sum is:  36
like image 32
Jeremy Friesner Avatar answered Oct 25 '22 10:10

Jeremy Friesner


All of the code below is is based on this article.


You can also do this kind-of C++11 "equivalent" of fold expressions:

#include <iostream>
#include <algorithm>
#include <utility>
#include <type_traits>
/*
Overload a total_sum() function with no arguments.
so it works when calling total_sum() with no argument.
*/
int total_sum()
{
    return 0;
}

template<typename ... I>
int total_sum(const I &... i)
{
    int result{};
    static_cast<void>(std::initializer_list<int>{(result += i, 0)... });
    return result;
}

int main()
{
    std::cout << total_sum() << '\n';
    std::cout << total_sum(1, 2, 5, 4, 2) << '\n';
    std::cout << total_sum(5, 6, 2) << '\n';
}

See this online!

This one can add anything that can convert to an add-able value:

#include <iostream>
#include <algorithm>
#include <utility>
#include <type_traits>

int total_sum()
{
    return 0;
}

template<typename ... V>
typename std::common_type<V...>::type total_sum(const V &... v)
{
    typename std::common_type<V...>::type result = {};
    static_cast<void>(std::initializer_list<int>{ (result += v, 0)... });
    return result;
}
int main()
{
    std::cout << total_sum() << '\n';
    std::cout << total_sum(5, 6, 2) << '\n';
}

See this online!

The code above can be cleaner using C++14:

#include <iostream>
#include <algorithm>
#include <utility>
#include <type_traits>

int total_sum()
{
    return 0;
}
template<typename ... V>
auto total_sum(const V &... v) {
  std::common_type_t<V...> result = {};
  static_cast<void>(std::initializer_list<int>{ (result += v, 0)... });
  return result;
}
int main()
{
    std::cout << total_sum() << '\n';
    std::cout << total_sum(5, 6, 2) << '\n';
}

See this online!

like image 20
justANewb stands with Ukraine Avatar answered Oct 25 '22 08:10

justANewb stands with Ukraine