2

I created a function like:

void triangle(int n, int start=1, int spcs=0, char dec_y='n', char lf='#',char decf='o') {
    //some code
}

I wanted to know is there any way that I could call this function like this:

triangle(9, dec_y='y', lf='&');

without doing this:

void triangle2(int nn, char d_ec_y, char llf) {
    triangle(nn, 1, 0, d_ec_y, llf, 'o');
}
// then in main simply
triangle2(9, 'y', '&');
xypnox
  • 166
  • 1
  • 12

4 Answers4

4

You can't change the order of the parameters. So you can't do what you want directly. You have three options:

  • One that you don't want to.
  • You can pass the parameters as structure. The struct can have default values. And you can only alter the ones which you want before calling the function.

For example:

struct params
{
    params(int n_)
     :n(n_)
    {
    }
    int start=1;
    int spcs=0; 
    char dec_y='n';
    char lf='#';
    char decf='o';
};

...
params p(0);
p.dec_y='y';
p.lf='&';
triangle(p);
  • You can use boost::parameter which provides exactly what you want. Check this question for a sample usage.
seleciii44
  • 1,529
  • 3
  • 13
  • 26
0

No, c++ requires that any parameters for which the default parameter will be used come after all specified parameters.

In some circumstances this can be worked around by having multiple overloads. But due to argument ambiguity that is not always possible. The idea is to leave out some of the middle arguments, as in:

void foo(int, char const *, int =0);
void foo(int, int=0);

This pair always requires the first int but allows that to be followed by either a string or another int, and if the string version is used still allows the final int argument.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
0

Using some advanced meta-programming it is actually possible to make all the arguments optional and to supply them in any order without declaring any overloads. For example this is implemented in boost.process API:

namespace bp = ::boost::process;
bp::environment env{::boost::this_process::environment()};
bp::child ch0("cmd", env); // ok
bp::child ch1("cmd", env, bp::windows::hide); // fine too
bp::child ch2("cmd", bp::windows::hide, env); // still fine
bp::child ch3("cmd", bp::windows::hide); // no problem

The idea behind this is that each supported argument is wrapped into a trait class that supplies manipulation method(s) and all those calls invoke the same template function which invokes manipulation method for each supplied argument.

user7860670
  • 35,849
  • 4
  • 58
  • 84
0

You might also overload your function several times to match all possible patterns, but it is a messy solution. For this, first of all, you might need to change your char parameters to either char* (C-style string) or std::string, because otherwise (if it even compiles) calling an overloaded function with different sized integer types (int and char) is ambiguous and may result in an undefined behavior.

void triangle(int n, int start=1, int spcs=0, std::string dec_y="n", std::string lf="#", std::string decf="o") {
    //some code
}

void triangle(int n, std::string dec_y="n", std::string lf="#", int start=1, int spcs=0, std::string decf="o") {
    //some code
}

Then you can write

triangle(9, "y", "&"); // using 2-nd overload (int, std:;string, std::string) where n=9, dec_y="y", lf="&"

but again, this is not really recommended, especially for functions with this much arguments, because it might (and will) mess the code up if there will be a need for more such overloads. Also, the problem with this solution is that if you won't pass any argument to the default parameter the call will also be ambiguous.

In my recent experience I've done a similar thing in my project when I decided to do this:

Node(std::string name, std::string path = "", Node* parent = NULL, int pos = -1);
Node(std::string name, Node* parent = NULL, int pos = -1, std::string path = "");

and that did work as a solution for me to make things easier when I wanted only to specify "path" leaving "parent" and "pos" with their defaults and vice versa.

NotYourFox
  • 35
  • 5