2

How to not get lost in that case ? Example, this is a function that returns bool but takes on 10 params:

bool myFunc(bool par1 = true, bool par2 = false, bool par3 = true,
  bool par4 = true /* and so on */ ) {}

And let's say that the function params are set default for 90% cases. But occasionally client code wants to change only a few of them. The only option I see here is painstakingly copy all the default params until we get to the one that needs to change. Any chance of calling this function in this way:

bool myVal = myFunc(par10 = true, par20 = false);

So any who reads the code know what is going (the names of the params are very long but meaningful) with the code and moreover when I change the function definition I won't need to look whenever it is called to update the default params ?

rsk82
  • 28,217
  • 50
  • 150
  • 240

5 Answers5

11

There is an idiom that is moderately famous: the Named Parameters Idiom.

The idea is simple:

class Parameters {
public:
    Parameters(): _1(true), _2(false), _3(true), _4(true) {}

    bool get1() const { return _1; }
    bool get2() const { return _2; }
    bool get3() const { return _3; }
    bool get4() const { return _4; }

    Parameters& set1(bool t) { _1 = t; return *this; }
    Parameters& set2(bool t) { _2 = t; return *this; }
    Parameters& set3(bool t) { _3 = t; return *this; }
    Parameters& set4(bool t) { _4 = t; return *this; }

private:
    bool _1;
    bool _2;
    bool _3;
    bool _4;
};

bool myFunc(Parameters p);

Then the client can do:

result = myFunc(Parameters());

Or:

result = myFunc(Parameters().set4(false));
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
2

Have a look at boost.parameter library.

Use this library to write functions and class templates that can accept arguments by name:

 new_window("alert", _width=10, _titlebar=false);
 smart_ptr<Foo, deleter<Deallocate<Foo> >, copy_policy<DeepCopy> > p(new Foo);

Since named arguments can be passed in any order, they are especially useful when a function or template has more than one parameter with a useful default value. The library also supports deduced parameters; that is to say, parameters whose identity can be deduced from their types.

bobah
  • 18,364
  • 2
  • 37
  • 70
1

That's one of the reasons such interfaces should be avoided. Create a wrapper to your func accepting a structure that contains all the parameters. On the client side instantiate the default configuration (have it available whenever you want to call your func; e.g. in object context). Whenever you want to call the func, copy the configuration to another instance, change the values you want and pass it to your wrapped func.

Or, even better, if possible, change the function signature directly without wrappers to accept the aggregated configuration.

SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
0

Use can use boost::bind (on C++03) or std::bind (on C++11) to reorder and fix some parameters to your function.

hate-engine
  • 2,300
  • 18
  • 26
0

If you have the case that some arguments make only sense in pairs, use overloaded functions.

So instead of e.g. (sorry, no better example now)

// Adds a new TODO. Either this is a low-prio TODO with no defined 
// deadline, xor a deadlined TODO for which year, month, day must
// be passed.
void add_todo (std::string description, int year=-1, int month=-1, int day=-1);

do

void add_todo (std::string description, int year, month, day);

void add_todo (std::string description) {
    add_todo(description, -1, -1, -1);
}

so to enforce one and only one of two possible call signatures.

Of course it would be better to add more structure, like Date. But even then, I do not advise to make Date "nullable" just for the sake of it:

void add_todo (std::string description, Date = Date::None); // <-- I wouldn't

but rather

void add_todo (std::string description);
void add_todo (std::string description, Date deadline);

or sometimes no overload and no defaults at all

void add_todo (std::string description);
void add_deadlined_todo (std::string description, Date deadline);
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130