Given the constraints, namely average of either two or three positive numbers, the second option is the best.
The first option, with the optional argument, requires a test for positivity:
int average(int x,int y,int z=-1) {
if (z<0) return (x+y)/2;
else return (x+y+z)/3;
}
In term of providing the service of finding an average, that test is unnecessary. Further, it is brittle: it's reasonable to consider finding the average of numbers that could also be negative, and this solution is not compatible with that case.
The third option, the variadic function, is inappropriate because you will need to provide information in the call to indicate how many arguments are present, e.g. with a terminating negative number, or with the first parameter indicating the number of remaining arguments. This complicates the interface. Further, it is not type safe, and the burden then rests on the users of the function to be scrupulous in calling it only with int
s — the compiler will not prohibit or warn about incorrect usage.
Using a variadic template is a good, general solution that extends easily to any number of parameters. Here though, we need only the two and three argument cases, and so it's overly complex for the application. If you were to use this though, you'd want to use a different implementation that did not require global variables. The following uses a namespace to hide some of the implementation details, and forces the use of int
arguments by fixing the head type before the recursion:
namespace impl {
int sum() { return 0; }
template <typename... V>
int sum(int a,V... rest) { return a+sum(rest...); }
}
template <typename... V>
int average(int a,V... rest) {
return impl::sum(a,rest...)/(1+sizeof...(V));
}