3

I have seen these questions:

but they do not consider variadic functions and variadic template .

Consider the problem of writing a function to find the average of either 2 or 3 positive numbers .

There are four ways we could implement this function:

  1. Using a default parameter:

    int average(int x , int y , int z=-1);
    
  2. Using function overloads:

    int average(int x , int y);
    int average(int x , int y , int z);
    
  3. Using a variadic function

    int average(int x,int y, ...);
    
  4. Using a variadic template

    int sum=0;
    int count=0;
    void average(){
       return;
    }
    template <class A, class ...B> void average(A argHead, B... argTail){
       sum =sum+argHead;
       count+=1;
       average(argTail...);
    }
    

What are the pros and cons of using one method over another ?

Community
  • 1
  • 1
sonus21
  • 5,178
  • 2
  • 23
  • 48
  • 1
    3 is not type-safe. And choosing between 1 and 2 depends on what the functions are doing. – Some programmer dude Mar 07 '15 at 07:26
  • 1
    As you can see all of them have to solve same problem . – sonus21 Mar 07 '15 at 07:26
  • 1
    Also, for number 3 you don't really know how many arguments there are, and you need to manually fetch the arguments from the stack and convert to the correct type (while hoping that the user passed correct values). – Some programmer dude Mar 07 '15 at 07:33
  • 1
    Regarding 1 and 2, for just this specific use-case, for 1 you have to keep a special case inside the function to check for `z` being `-1` and not use the variable in that case. With method 2 you don't need any special cases. – Some programmer dude Mar 07 '15 at 07:34
  • @JoachimPileborg You are providing differences not pros and cons . – sonus21 Mar 07 '15 at 07:37
  • I would argue that lack of type-safety and not knowing the argument count are definitive cons, as is the use of special cases. My suggestion is that you implement all three, see which one you like best, and then do performance testing on them. – Some programmer dude Mar 07 '15 at 07:38
  • Agree for 3rd case but what about 1 and 2 case ? – sonus21 Mar 07 '15 at 07:39
  • Why do you think he highlights differences rather than "pros and cons"? Because they are different and suited for different use cases :). Furthermore, in the first case, what would happen if I do `average(9,1,-1)`? I'ld get `5` instead of `3` as my last number would be ignored. – Rerito Mar 07 '15 at 08:09
  • @Rerito It has been mentioned that find average of only +ve numbers .They all works in same way except putting some extra logic and extra code but there may be some pros of using one above another that i would like to now . – sonus21 Mar 07 '15 at 08:13
  • Then write the word in _full letters_, I read the `+ve` as a typo... – Rerito Mar 07 '15 at 08:14
  • "array should not be used". I'm curious as to why this stipulation, if you don't mind my asking. – Taekahn Mar 07 '15 at 08:21
  • What about a variadic template? – Peter - Reinstate Monica Mar 07 '15 at 08:42
  • @Taekahn just for fun . If we can pass array there is no need of these three types we can just write a single function and done. – sonus21 Mar 07 '15 at 08:50
  • @JoachimPileborg pity to close this, it's a lovely question imo. Too broad, heck yeah, so what. There are far too many narrow and narrowminded questions on SO. Only issue one could have: it may be better suited over in codereview. – Peter - Reinstate Monica Mar 07 '15 at 18:13
  • @PeterSchneider can you move to codereview section ? – sonus21 Mar 07 '15 at 18:24
  • I flagged it for moderator review because I (or any normal user., I think) cannot move it. I also read in http://meta.stackexchange.com/questions/89799/how-to-migrate-to-code-review that one criteria for suitability in codereview is "Is it actual code from a project rather than pseudo-code or example code?"; I think you presented example code, which may be considered OT in cr, which apparently tries to be a review site for "real code", whatever that is. – Peter - Reinstate Monica Mar 09 '15 at 10:58
  • @PeterSchneider Thanks . Yes this is a example code . Actually i was doing my assignment where i need overload a function with one extra arguments (both function were doing same thing except one extra `print statement` based on third argument ) then i thought let's see which one could do better since we can achieve same thing in different way . – sonus21 Mar 09 '15 at 12:43

1 Answers1

1

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 ints — 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));
}
halfflat
  • 1,584
  • 8
  • 11