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
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.
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).
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.
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.
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);
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
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!
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