Search code examples
c++templatesc++14variadic-templates

Function overloading inside overloaded function


I am using C++14 (and pretty new to it). I have 3 overloaded functions func within which another overloaded function do_something gets called depending on its parent function (func).

int func(int a) {
   bar(a);
   foo();
 }

int func(int a, float b) {
   bar(a);
   do_something(b);
   foo();
}

int func(int a, float b, char c) {
   bar(a);
   do_something(b, c);
   foo();
 }

I see that the functionality within func is almost the same except which version of do_something gets called. Is there any way I can make this generic and combine all func's together?


Solution

  • To begin with, make func a template that accepts a parameter pack. The int a argument, the call to bar and the call to foo are always there, so that's simple. Let's add a placeholder for do_something for now.

    template <class ...Args>
    int func(int a, Args&&... other)
    {
       bar(a);
       // somehow call do_something and do the right thing
       foo();
    
       return 0;
    }
    

    You want to instantiate and invoke the above template as before:

    func(42);
    func(42, 1.f);
    func(42, 1.f, 'A');
    

    Now let's tackle the call to do_something. If you simply add it in the middle of the new func template;

    do_something(std::forward<Args>(other)...);
    

    this refuses to compile for func(42), i.e., the case with only one argument. Hence, we need a special case for this. One way to achieve this in another level of indirection for do_something:

    // No additional argument case, does nothing:
    void do_something_wrapper() {}
    
    // The other two cases    
    template <class ...Args>
    void do_something_wrapper(Args&&... args)
    {
       do_something(std::forward<Args>(args)...);
    }
    

    And now, the placeholder from the func function template should be:

    do_something_wrapper(std::forward<Args>(other)...);