This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Variable number of arguments in C++?
May I not set the number of arguments of a function with variable number of arguments? As an example: can the following interface be implemented?
int sum(...) { ... }
sum(1, 2, 3, 4); // return 10
Conventional variadic functions are messy and not type-safe, but in C++11 you can do this cleanly using variadic templates and (compile-time) recursion:
// Base case for recursion
template <typename T>
inline T sum(T n) {
return n;
}
// Recursive case
template <typename T, typename... Args>
inline T sum(T n, Args... args) {
return n + sum(args...);
}
Since it's a template, this'll work for any types that have an operator+ defined:
std::cout << sum(1, 2, 3) << std::endl; // Prints 6
std::cout << sum(3.14, 2.72) << std::endl; // Prints 5.86
However, because the return type of the recursive template function is taken from the first argument only, you can get suprising results if you mix different argument types in one call: sum(2.5, 2) returns 4.5 as expected, but sum(2, 2.5) returns 2 because the return type is int, not double. If you want to be fancy, you can use the new alternative function syntax to specify that the return type is whatever the natural type of n + sum(args...) would be:
// Recursive case
template <typename T, typename... Args>
inline auto sum(T n, Args... args) -> decltype(n + sum(args...)) {
return n + sum(args...);
}
Now sum(2.5, 2) and sum(2, 2.5) both return 4.5.
If your actual logic is more complex than summation, and you don't want it inlined, you can use the inline template functions to put all the values into some sort of container (such as a std::vector or std::array) and pass that into the non-inline function to do the real work at the end.
You probably want to do this by writing the function to take something like a vector<int>, which you'll construct on the fly with a braced initializer list:
int sum(std::vector<int> const &n) {
return std::accumulate(begin(n), end(n), 0);
}
If there's some possibility the numbers might be (for example) floating point instead, you probably want to write it as a template instead:
template <class T>
T sum(std::vector<T> const &n) {
return std::accumulate(begin(n), end(n), T());
}
Either way, you'd invoke this just marginally differently:
int x = sum({1,2,3,4});
Warning: this feature was added to C++ fairly recently, so some compilers (e.g., VC++) don't support it yet -- though others (e.g., g++ 4.7+), do.
No, you can't.
Just don't use variable arguments. They suck in every conceivable fashion and are completely not worth anybody's time.
A C++ variadic function must know how many (and what type) of arguments it was passed. For example, printf's format string tells it what extra arguments to expect.
Your sum has no way of knowing if it got 4 ints or 10. You could make the 1st argument a length:
int sum(int howmany, ...) { ... }
so the function knows how many ints follow. But really you should just pass an array (or vector if you're feeling C++'y)
There are multiple ways to solve your issue. I'll go over a few:
Method 1:
-Create a series of overloaded sum functions to suit your needs.
Cons
-code bloat
This can be implemented by making multiple functions with headers:
int sum(int a);
int sum(int a, int b);
int sum(int a, int b, int c);
etc...
Method 2:
-create a custom class with a linked list, and pass in a pointer to the head of the linked list. This is probably your best move in this case, assuming you don't know the amount of data to be passed in.
Function header:
int sum(LinkedList *headPointer);
Method 3:
-pass in an array of variables
Function header:
int sum(int input[]);
Method 4:
-create a function with auto-set variables
Function header:
int sum(int a=0, int b=0, int c=0, int d=0,... int n=0);
Related
Suppose I have the following function template:
int bar();
template <std::size_t... Is>
void foo()
{
constexpr auto N = sizeof...(Is);
int a[N] {/* magic here, like bar()... */};
}
I want to initialize the array a with N bar()s. The first solution I came up with is like the following:
int a[N] {(Is, bar())...};
But it results in some "expression result unused" warnings.
LIVE EXAMPLE
How can I get rid of these warnings if I don't want to turn off the -Wunused-value flag? Or is there any other way to write N bar()s? It is better that the solution works not only for bar(), but also for any expression that does not depend on Is.
Edit: the use of initializing an array is only an example. There are many other contexts that require such a sequence of expressions (for example, use for arguments of another template). So what I really want is how to generate such a sequence rather than to initialize the array.
One possible way is to silent the warning locally, as casting to void:
int a[N] {(static_cast<void>(Is), bar())...};
Demo
This solution requires two steps, but you could do something like initialize the array, then std::fill_n with values.
template <std::size_t... Is>
void foo()
{
constexpr auto N = sizeof...(Is);
int a[N];
std::fill_n(a, N, bar());
}
I am creating a library for myself that contains functions and macros for things I use often and don't want to constantly retype or copy/paste (sometimes hundreds of lines long). I have a chunk of code in an old project that I have to copy and paste constantly and then change all the variable names to fit my current project. I want to turn the chunk of code into a function in my library.
The big chuck of code formats output into a box so if the output is too long it doesn't ruin any borders I may have or go right to the edge of the console (which bothers me). The user passes the top-left corner of the box and provides the x coordinate of the right edge that the text should not pass. The rest of the arguments are the variables or literals to be outputted. The chunk of code puts all the variables and literals into one big string which is then outputted char by char until the output reaches the x boundary. The output then continues at the x coord of the top-left corner and one line down.
In order for this to work the function must have a varadic template to allow for variable amounts of multiple types of output (similar to cout << "I have " << 4.5 << " cookies and " << 2 << " friends.").
The template is complete and works until I try to create an array of the template type and initialize it.
template<typename ...Inputs>
void textBox(int x, int y, int xBoundary, const Inputs&... things) {
Inputs arr[sizeof...(things)] = {things...};
}
At this point I get this error: parameter packs not expanded with '...' Note: 'Inputs'
I have used this type of thing before but all the inputs were of the same type for that function so I could easily just do this:
template<typename ...Inputs>
void textBox(int x, int y, int xBoundary, const Inputs&... things) {
std::string arr[sizeof...(things)] = {things...};
}
That gives no errors unless of course the user tries to pass something other than a string so I know that my error has something to do with making the array of template type. Any help would be appreciated!
Arrays need to contain elements of the same types - they are not heterogeneous data structures. In your case Inputs is a pack containing all the types of things... which is not expanded, which is why you are getting an error.
Use std::tuple instead, which is an heterogeneous container:
std::tuple<std::decay_t<Inputs>...> tuple{things...};
Or std::make_tuple:
auto tuple = std::make_tuple(things...);
In C++17, the template parameters might be omitted thanks to class template argument deduction:
std::tuple tuple{things...};
If you want to iterate over things..., it's best to not put them in a std::tuple. In C++17, you can use a fold expression to print all of them:
(std::cout << ... << things);
In C++11, you can define a pseudo-recursive variadic template:
template <typename T>
void print(const T& x)
{
std::cout << x;
}
template <typename T, typename... Rest>
void print(const T& x, const Rest&... rest)
{
print(x);
print(rest...);
}
I would like to compute the function composition -- f ( g (param) ). Here is what I tried:
auto fComposition(auto&& f, auto&& g, auto&&... params)
{
/* some stuff */
auto result = std::forward<decltype(f)>(f)(
std::forward<decltype(g)>(g)(
std::forward<decltype(params)>(param)
)
);
/* other stuff */
return result;
};
Compiling with
g++ -std=c++17 src.cpp
basic test
#include <random>
#include <math.h>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> distr(-1.0, 1.0);
auto xx = fComposition(round, distr, gen);
return 0;
}
I've got the message that it doesn't recognize the type of first function .
BTW, is this really your code? You're not expanding params so it should not compile.
I. The way you define composition, it is indistinguishable from a simple invocation: your fComposition(f, g, arg) is the same as f(g(arg)) except for extra characters typing. The real composition is usually a combinator that accepts two functions and returns a closure that, when invoked on actual arguments, applies them in succession. Something like:
template<class F, class G> auto comp(F f, G g) {
return [f, g](auto &&... args) {
return f(g(std::forward<decltype(args)>(args)...));
};
}
(Note by-values bindings. In C++17, they are more advanced than twenty years ago. :) You can add std::moves and std::forwards by taste.)
This way you compose two functions:
auto fg = comp(f, g);
and later invoke the result on arguments:
auto x = fg(arg1, arg2);
II. But really, why limit ourselves with two operands? In Haskell, (.) is a single binary function. In C++, we can have a whole tree of overloads:
template<class Root, class... Branches> auto comp(Root &&root, Branches &&... branches) {
return [root, branches...](auto &&...args) {
return root(branches(std::forward<decltype(args)>(args)...)...);
};
}
Now you can encapsulate any AST in a single callable:
int f(int x, int y) { return x + y; }
int g(int x) { return x * 19; }
int h(int x) { return x + 2; }
#include <iostream>
int main() {
auto fgh = comp(f, g, h);
std::cout << fgh(2) << '\n';
}
A similar technique was the only way known to me to have anonymous closures in C++ prior to 11 standard.
III. But wait, is there a library solution? In fact, yes. From std::bind's description
If the stored argument arg is of type T for which std::is_bind_expression<T>::value == true (for example, another bind expression was passed directly into the initial call to bind), then bind performs function composition: instead of passing the function object that the bind subexpression would return, the subexpression is invoked eagerly, and its return value is passed to the outer invokable object. If the bind subexpression has any placeholder arguments, they are shared with the outer bind (picked out of u1, u2, ...). Specifically, the argument vn in the std::invoke call above is arg(std::forward<Uj>(uj)...) and the type Vn in the same call is std::result_of_t<T cv &(Uj&&...)>&& (cv qualification is the same as that of g).
Sorry, no examples here at this moment. >_<
P.S. And yes, std::round is an overloaded function so you should typecast it to specify which exactly overload you need to be composed.
The include of random includes cmath, which in libstdc++ also defines several of the math operators (including round) in the default namespace as well as in the std namespace. (See this answer for the rationale.) And C++'s round has multiple overloads. As a result, you have several versions of round available, and your function doesn't know which round you want to use, thus the error message about ambiguity. The correct solution is to disambiguate which round you mean. You can do this with a static cast:
static_cast<double(*)(double)>(round)
Since you have to go through the trouble anyway, you may as well also use the cmath header instead of math.h and use std::round instead. At least then you know that it's going to be overloaded up front.
I'm trying to find a good solution for the following problem:
I want to implement a function that takes a variable number of container arguments and returns the size of the biggest container. Here is an example:
std::vector<std::string> vStr(2, "foo");
std::vector<int> vInt(1, 123);
std::vector<double> vDouble(3, 1.1);
std::list<char> lChar(4, '*');
// or even more container
size_t uiMaxSize = getMaxContainerSize(vStr, vInt, vDouble, lChar /*, ...*/);
in this case getMaxContainerSize should return 4, because lChar has the biggest size of 4.
I've already implemented this workaround using cstdarg:
#include <cstdarg>
...
size_t getMaxContainerSize(int iCnt, ... )
{
size_t uiMaxSize = 0;
va_list ap;
va_start(ap, iCnt);
for(int i=0; i<iCnt; i++)
{
size_t uiTempSize = va_arg(ap, size_t);
uiMaxSize = uiMaxSize<uiTempSize ? uiTempSize : uiMaxSize;
}
va_end(ap);
return uiMaxSize;
}
...
size_t uiMaxSize = getMaxContainerSize( 4, vStr.size(), vInt.size(), vDouble.size(), lChar.size());
But with this I have to type .size() for every container and I also have to specify the number of containers. I also don't like to use C stuff in C++ programs and I'm asking myself if there is a better way to implement this. Maybe by using some class and overloading operator<<() so I can type something like this:
MaxSizeFinder cFinder;
cFinder << vStr << vInt << vDouble << lChar;
size_t uiMaxSize = cFinder.getResult();
Do you think something like this is possible? Any suggestions?
Thank you.
Use a variadic template:
template<typename... Conts>
std::ptrdiff_t getMaxContainerSize(const Conts&... conts) {
return std::max({conts.size()...});
}
When you pass containers as arguments, the compiler will deduce a list of types for Conts. Each parameter of the function will be a const <deduced type> &*. Using conts.size()... expands to conts1.size(), conts2.size(), ..., contsN.size(), where conts# is each argument given to the function. It turns out std::max has a handy overload that you can delegate this to.
There are a couple key advantages of variadic templates over C variadic functions:
They are type safe - the compiler is guaranteed to complain when types don't match, and you don't need a format string or anything.
The function knows how many arguments were passed, and you can get it with sizeof...(Conts).
Nothing special happens to the arguments when going in. In a variadic function, char would be an int by the time the function has to pick it out, among others.
You don't need to explicitly specify any of the types when you use the arguments. This means you can accept an infinite number of types instead of a predefined list (think printf's format specifiers).
Finally, per the comments, the return type was changed to a signed type that mostly acts as the signed counterpart to size_t (sort of like the non-standard ssize_t).
To future-proof the answer, there will soon be a std::size for a more generic way to get a container's size:
using std::size;
return std::max({size(conts)...});
This expands similar to above: size(conts1), size(conts2), ..., size(contsN)
*Normally, parameter packs are used with T&&... with std::forward instead of const T&.... This would potentially buy you something with third-party classes that have a more efficient size function when the object used is an rvalue. However, it adds complexity in general for a low chance at any benefit.
So I have a function that takes a variable length argument list, for example:
int avg(int count,...){
//stuff
}
I can call it with avg(4,2,3,9,4); and it works fine. It needs to maintain this functionality.
Is there a way for me to also call it with an array instead of listing the variables? For example:
avg(4,myArray[5]) such that the function avg doesn't see any difference?
No there is no such way. You can however make two functions, one that takes a variable number of arguments, and one that takes an array (or better yet, an std::vector). The first function simply packs the arguments into the array (or vector) and calls the second function.
void f() {}
template<typename T, std::size_t N>
void f(T array[N])
{
}
template<typename T, typename... Args>
void f(const T& value, const Args&... args)
{
process(value);
f(args...);
}
No. Since pointers are essentially unsigned integers it would not be able to tell the difference between a memory address and an unsigned integer. Alternatively (as I am sure you wanted to avoid), you would have to do:
avg( 4, myArray[ 0 ], ..., myArray[ 3 ] );
... where ... is myArray at positions 1 and 2 if you wanted to conform with the same parameters as your previous function. There are other ways to do this, such as using C++ vectors.
You can easily do it
struct{int arr[100];}p;
double avg2(int count,int* arr){
memcpy(&p,arr,count*sizeof(int));
return avg(count,p);
}
Better approach would be get rid of variadic arguments. This was inherited from C and it is a good practice to avoid it as much as possible.
Now your example avg(4,myArray[5]) is a bit fuzzy. I assume, that first argument defines how much items must be taken from array and second argument you planned to pass just an array. I assume this index operator is typo or limping method showing array size.
So you expect something like this:
int avg(int count, ...)
{
int sum = 0;
std::va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
sum += va_arg(args, int);
}
va_end(args);
return sum / count;
}
template <size_t N, size_t... I>
int avg_helper(size_t count, const int (&arr)[N], std::index_sequence<I...>)
{
return avg(count, arr[I]...);
}
template <size_t N>
int avg(int count, const int (&arr)[N])
{
if (count > N)
throw std::invalid_argument { "to large count passed" };
return avg_helper(count, arr, std::make_index_sequence<N> {});
}
https://godbolt.org/z/7v1n7zaWq
Now note that in overload resolution variadic function is match as a last one. So when compiler can match template it will select it instead variadic function.
Note there is a trap. If you will pass a pointer (for example array decay) variadic argument function will kick in again. So as protection I've added extra overload which will trigger static_assert warning about array decay.