#include <iostream>
#include <cstdarg>
using namespace std;
double average(int num, ...)
{
va_list arguments; //a place to store the list of arguments
double sum = 0;
va_start(arguments, num); //initializing arguments to store all values after num
for(int i = 0; i < num; i++) //loop until all numbers are added
{
sum += va_arg(arguments, double); //adds the next value in argument list to sum
}
va_end(arguments); //cleans up the list
return sum / num; //casting ensures accuracy
}
int main()
{
cout << average(5, 10) << '\n';
return 0;
}
What is wrong with this code? (variable argument lists in C++)
I'm following the code here:
http://www.cprogramming.com/tutorial/lesson17.html
That code, when copied and pasted, works. However, when I run my own code (which is basically the code from the site, except not CP'ed), I get garbage for output. I've looked my code over and I don't see how it differs from the code on the website except for spacing and variable names. Could someone take a look and see what I'm doing wrong?
Ohhh. I'm an idiot. Num is the amount of arguments passed to the function. I should have known that. Thanks.
Now that you know how this works, please don't do it any more in C++. There are many limitations and subtle gotchas for a "convenience" that that isn't really.
And now for something completely different.
EDIT: Fixed
NOTE: To use, remove whitespaces trailing backslashes added to prevent gdnet from joining all the lines.
And now for something else completely different.
#include <boost/preprocessor.hpp>#include <cassert>#define AVERAGE_ADD_IMPL(z,n,arg) + arg ## n#define AVERAGE_IMPL(z,n,unused) \ template < typename T > T average( BOOST_PP_ENUM_PARAMS( n, T arg ) ) { \ return ( BOOST_PP_REPEAT( n, AVERAGE_ADD_IMPL, arg ) ) / n; \ }BOOST_PP_REPEAT_FROM_TO( 1, 11, AVERAGE_IMPL, ~ )#undef AVERAGE_IMPL#undef AVERAGE_ADD_IMPLint main() { assert( average(1,2,3,4,5) == 3 );}
EDIT: Fixed
NOTE: To use, remove whitespaces trailing backslashes added to prevent gdnet from joining all the lines.
And now for something else completely different.
template < typename T, typename Iterator > T average( Iterator begin, Iterator end ) { unsigned n = 0; T value = T(); for ( Iterator i = begin ; i != end ; ++i, ++n ) { value += *i; } return value / n;}template < typename T, unsigned N > T average( const T (&array)[N] ) { return average<T>( array+0, array+N );}int main() { int values[] = { 1, 2, 3, 4, 5 }; assert( average(values) == 3 ); std::list<int> container; container.push_back(1); container.push_back(2); container.push_back(3); container.push_back(4); container.push_back(5); assert( average<int>( container.begin(), container.end() ) == 3 );}
Quote:Original post by MaulingMonkeytemplate < typename T, typename Iterator > T average( Iterator begin, Iterator end ) { unsigned n = 0; T value = T(); for ( Iterator i = begin ; i != end ; ++i, ++n ) { value += *i; } return value / n;}
Bug: for an arbitrary type, the default constructor is not guaranteed to be the additive identity. Instead, if begin != end, you should copy construct from the first element instead, and start your loop from begin+1.
Bug: if begin == end, you divide by zero. This is undefined behavior. You should detect the condition and do something sane.
Quote:Original post by frob
Bug: if begin == end, you divide by zero. This is undefined behavior. You should detect the condition and do something sane.
Average of zero numbers is undefined per se, and should trigger a division by zero exception.
There's nothing else you can return in this case, at least not with function in this form.
I once wrote some weird template code where you could pass the number of arguments as a template parameter. I cannot, for the life of me, remember how I did that... probably for the best anyway, I'm sure it was full of bugs.
I can't see any weaknesses with something like this compared to the above samples
template<typename T>class Accumulator{ T sum; int count;public: Accumulator() : sum(0), count(0) {} friend Accumulator& operator << (Accumulator& a, T number) { a.sum += number; a.count++; return a; } void reset() { sum = 0; count = 0; } T average() const { return sum / count; }};#include <iostream>int main(){ Accumulator<double> accumulator; accumulator << 3.0 << 4.3 << 5.8 << 6.2 << 7.0; std::cout << "Average: " << accumulator.average() << std::endl;}
Why not std::accumulate?
T average = std::accumulate(begin, end, T()) / std::distance(begin, end);
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement