I don't understand functions that accept a variable number of arguments. I want to make a program with a max function taking any number of type double and returns the greatest of them

Recommended Answers

All 16 Replies

see this thread that was posted only a couple hours ago.

> I want to make a program with a max function taking any number of type double
> and returns the greatest of them.
So store them in an array (or better yet, a vector) and write a function which accepts that array (or better yet, a vector).

The first thing you need to realise is that variadic functions have NO TYPE CHECKS beyond the fixed parameters. Which means that you have lots of wonderful ways of screwing up the code in many new and interesting ways. Just look on the C forum to see how many times people mess up say scanf() by forgetting an &.

> I want to make a program with a max function taking any number of type double and returns the greatest of them

for a small number of arguments (upto about seven or so), you could use overloaded function names.

#include <iostream>
#include <algorithm>
template< typename T > inline
const T& max( const T& a, const T& b, const T& c )
{ return std::max( std::max(a,b), c ) ; }

template< typename T > inline
const T& max( const T& a, const T& b, const T& c, const T& d )
{ return std::max( std::max(a,b), std::max(c,d) ) ; }

template< typename T > inline
const T& max( const T& a, const T& b, const T& c, 
              const T& d, const T& e )
{ return std::max( std::max(a,b), max(c,d,e) ) ; }

template< typename T > inline
const T& max( const T& a, const T& b, const T& c, 
              const T& d, const T& e, const T& f )
{ return std::max( max(a,b,c), max(d,e,f) ) ; }

template< typename T > inline
const T& max( const T& a, const T& b, const T& c, const T& d, 
              const T& e, const T& f, const T& g )
{ return std::max( max(a,b,c,d), max(e,f,g) ) ; }

template< typename T > inline
const T& max( const T& a, const T& b, const T& c, const T& d, 
              const T& e, const T& f, const T& g, const T& h )
{ return std::max( max(a,b,c,d), max(e,f,g,h) ) ; }

int main()
{
  std::cout << max( 12.3, 4.5, 67.8, 9.98, 76.5, 4.3, 2.1, 0.0 ) << '\n' ;
}

> I want to make a program with a max function taking any number of type double and returns the greatest of them

for a small number of arguments (upto about seven or so), you could use overloaded function names.

And just how would that help the OP create a function that takes a variable number of arguments ? At least two problems with the templates you posted: (1) none of them take a variable number of arguments, and (2) the arguments are all the same data type, which is not necessarily the case with functions that take a variable number of arguments.

Member Avatar for iamthwee

You should be glad he didn't use the boost libraries. lolz

> just how would that help the OP create a function that takes a variable number of arguments
you can call max with anything between 2 to 8 arguments; that is a variable number in my book. in any case, the C++ standard recommends some minimum values for such things as the maximum number of arguments for a function(256), the maximum nesting level of compound statements (256) etc. compilers can exceed these, but variable number of arguments does have an upper limit, no matter what technique you use. in my example, the upper limit is 8 (a reasonable value according to me. others may have different idea of what would be a reasonable value for an upper limit on number of arguments to be passed to a function. and they can create more overloads of max if they want).

> the arguments are all the same data type
yes, the OP wanted all arguments to be double values. and finding the largest implies that all arguments must support comparisons between them.

> You should be glad he didn't use the boost libraries. lolz
yes, you should be glad. i did considor using the boost preporocessor metaprogramming library http://www.boost.org/libs/preprocessor/doc/index.html to generate the overloaded max functions. but dropped the idea as i thought it may confuse many people.

> just how would that help the OP create a function that takes a variable number of arguments
you can call max with anything between 2 to 8 arguments; that is a variable number in my book. .

But a very poor implementation because you had to create a template for each number of arguments -- 8 arguments = 8 templates. What if he wants 50 arguments, do you want to write 50 templates ? that's why varargs.h is a better solution -- not perfect as Salem pointed out, but workable. One function -- an infinite (almost) number of arguments, and you don't have to screw around writing millions of templates or overloaded functions.

As for boost libraries -- I don't know, but it might have a better solution.

> What if he wants 50 arguments, do you want to write 50 templates ?
no. i would strongly discourage him from trying to write functions which need more than seven or eight arguments.

> One function -- an infinite (almost) number of arguments
with the template: One function -- an infinite (almost) number of types.
and completely typesafe.

> and you don't have to screw around writing millions of templates or overloaded functions.
with the template: you don't have to screw around breaking your code each time (i suppose you would say millions of times) a new type needs to be supportd.

all my attempts at generating the functions using boost.preprocessor have resulted in code that was difficult to read and difficult to debug. (i really do not know how to debug preprocessor code other than by looking at the generated cpp output. and none of the versions i tried ended up being very readable).

but there is good news. c++ programmers will never have to use the unsafe and error-prone <cstdarg> ; c++0x has a solution. using variadic templates, we can write a typesafe function taking an arbitrary number of arguments of arbitrary types. http://en.wikipedia.org/wiki/C++0x#Variadic_templates

here is how you would write largest_of a variable number of values in c++0x.

#include <iostream>
#include <string>
// compile with gcc 4.3 with the -std=c++0x switch

template< typename T > inline 
const T& largest_of( const T& a, const T& b )
{ return a>b ? a : b ; }

template< typename T, typename ...REST > inline
const T& largest_of( const T& first, const REST&... rest... )
{ return largest_of( first, largest_of( rest... ) ) ; }

int main()
{
  std::cout << largest_of( 1, 9, 2, 8, 3, 7, 4, 6, 5 ) << '\n' ;
  std::cout << largest_of( 5.3, 8.9, -3.2, 17.8, 4.2, 7.0 ) 
          << '\n' ;
  const std::string s1("abc"), s2("2345"), 
                 s3("vufuk"), s4("ffyfyu") ;
  std::cout << largest_of( s1, s2, s3, s4 ) << '\n' ;
}
/**
>g++43 -Wall -std=c++0x -pedantic -Werror largest_of.cc && ./a.out
9
17.8
vufuk
*/

>
but there is good news. c++ programmers will never have to use the unsafe and error-prone <cstdarg> ; c++0x has a solution. using variadic templates, we can write a typesafe function taking an arbitrary number of arguments of arbitrary types. http://en.wikipedia.org/wiki/C++0x#Variadic_templates

here is how you would write largest_of a variable number of values in c++0x.

#include <iostream>
#include <string>
// compile with gcc 4.3 with the -std=c++0x switch

template< typename T > inline 
const T& largest_of( const T& a, const T& b )
{ return a>b ? a : b ; }

template< typename T, typename ...REST > inline
const T& largest_of( const T& first, const REST&... rest... )
{ return largest_of( first, largest_of( rest... ) ) ; }

int main()
{
  std::cout << largest_of( 1, 9, 2, 8, 3, 7, 4, 6, 5 ) << '\n' ;
  std::cout << largest_of( 5.3, 8.9, -3.2, 17.8, 4.2, 7.0 ) 
          << '\n' ;
  const std::string s1("abc"), s2("2345"), 
                 s3("vufuk"), s4("ffyfyu") ;
  std::cout << largest_of( s1, s2, s3, s4 ) << '\n' ;
}
/**
>g++43 -Wall -std=c++0x -pedantic -Werror largest_of.cc && ./a.out
9
17.8
vufuk
*/

Greate news for the graduating Class of 2020. There are no compilers that support it since the standards have not been approved yet so we still have to resort to stdarg.h to get variable argument functions.

> There are no compilers that support it
the output that i posted is with the code compiled by gcc 4.3 today; they are not my visualization of how it would look like in 2020.

> we still have to resort to stdarg.h to get variable argument functions
you may have to. i do not. even without gcc 4.3.

> There are no compilers that support it
the output that i posted is with the code compiled by gcc 4.3 today; they are not my visualization of how it would look like in 2020.

You are fortunate -- I tried it with VC++ 2005 Express and Dev-D++ Version 4.9.9.2 and they both puked out lots of errors.

> we still have to resort to stdarg.h to get variable argument functions you may have to. i do not. even without gcc 4.3.

Apparently I'm not alone! I suspect you think everyone should abandon their compilers and get gcc 4.3 (note: I'm not trying to insult you here, just poking a little fun) :)

no. i really meant even without gcc 4.3
i would use something like a std::vector< boost::any >
or a std::list< boost::variant<int,double,std::string> >
both of which are typesafe. and i would get the same functionality.
i also would not write functions that took several dozens of arguments; so even the overloaded template technique would be quite adequate for my limited needs.

commented: great solution +20

Yes, I agree that is a much better solution. With vector or list there is no need for stdarg.h or for writing an infinite amount of templates.

Thanks much for all the help, I figured it out with all the suggestions

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.