Skip some arguments in a C++ function?

I have a C++ function that has 5 arguments, all of which have default values. If I pass in the first three arguments, the program will assign a default value to the last two arguments. Is there any way to pass 3 arguments, and skip one in the middle, giving values to say, the first, second, and fifth arguments?


Solution 1:

Not directly, but you might be able to do something with std::bind:

int func(int arg1 = 0, int arg2 = 0, int arg3 = 0);

// elsewhere...
using std::bind;
using std::placeholders::_1;
auto f = bind(func, 0, _1, 0);

int result = f(3); // Call func(0, 3, 0);

The downside is of course that you are re-specifying the default parameters. I'm sure somebody else will come along with a more clever solution, but this could work if you're really desperate.

Solution 2:

With a classical 5 arguments function, there is no way to give it only 3 or 4. You can only write 3 or 4 with default arguments but at the end you will get a function call with 5 arguments.

There are also issues with you system if there are several parameters with the same type. For instance, if you have foo(int a=4,int b=5) and call foo(10), how do you know you want to call foo(10,5) or foo(4,10) ?

With C++11 tuples and Named parameters idiom, you can cheat it a little bit.

#include <iostream>
#include <functional>
#include <tuple>
#include <string>

struct f_
{
    private:

    typedef std::tuple<int,int,double> Args;

    //default arguments
    static constexpr const Args defaults = std::make_tuple(10,52,0.5);
    Args args;
    public :
    f_():args(defaults)
    {}

    template <int n,class T> f_& setArg(T&& t)
    {
        std::get<n>(args) = t;
        return *this;
    }

    void operator()() 
    {
        return (*this)(std::move(args));
    }

    void operator()(Args&& a)
    {
        int n1=std::get<0>(a);
        int n2=std::get<1>(a);
        double n3=std::get<2>(a);

        std::cout<<n1<<" "<<n2<<" "<<n3<<std::endl;
    }
};
#define set(n,v) setArg<n>((v))
int main()
{
    //f_().set<1>(42).set<3>("foo") ();
    f_().setArg<1>(42)(); //without Macro
    f_().set(0,666).set(1,42)(); //with Macro
    f_()(); //without any parameters
    f_()(std::forward_as_tuple(-21,-100,3.14)); //direct call
}

An alternative method is to use std::bind as described there