Learn how to support named parameters in C++

Posted: May 27, 2011 in Programming Recipes
Tags: ,

A common problem of (not only) C++ is that it only supports positional parameters: a caller of a function has to list its parameters according to the order declared in the method’s signature. Suppose you are refactoring an old code that supports the manufactoring of a big car company. You have to create cars by using a constructor that receives a bunch of parameters (assume you have neither setters nor other ways to fully construct a car):


Car* car = new Car (model, hp, year, doors_number, ... );

I find this code terribly bad. What about readability? (what does the first paramater mean? And the second? …) Modifiability? (what if I’d like to add other information?). Etc.

Why not writing something like:


Car myCar = CarMaker (year)

   .model (myCarModel)

   .hp (myCarHP)

   .doors_number (myCarDoorsNumber)

   . ...

The idea is to change the function’s parameters to methods of a newly created class, where all these methods return *this by reference. Notice how the “parameters” are in random order and they all have names. You can implement some variants of this approach but the concept is always the same: to avoid positional parameters.

Ok, let’s go through implementation details.

First, we create a class (CarMaker) that houses all the parameter values as private data members. The required parameters (the year, in our example – assume you can’t set a default year) is implemented as normal (positional parameter) on CarMaker’s constructor, but that constructor does not actually create the car. Then, all the optional parameters become methods. They return a reference to their “this object”, so the method calls can be chained.

class CarMaker {

public:

     CarMaker (uint year);

     CarMaker& model (string const&); // changes the model
     CarMaker& hp (uint); // changes the hp
     CarMaker& doors_number (uint); // changes the number of doors

     // ...

private:

      friend class Car;

      uint year;
      string model;
      uint hp;
      uint doors_number;

      // ...
};

inline CarMaker::CarMaker(uint _year) // some "standard" values
      : year (_year)
      , model ("unspecified")
      , hp (1000) // we sell sport cars!
      , doors_number (5)
{ }

inline CarMaker& CarMaker::model (string const& _model)
{
     model = _model;
     return *this;
}

inline CarMaker& CarMaker::hp (uint _hp)
{
     hp = _hp;
     return *this;
}

inline CarMaker& CarMaker::doors_number (uint _doors_number)
{
     doors_number = _doors_number;
     return *this;
}
// ...

CarMaker declares Car as its friend, that way it does not need a bunch of public get methods.

At this point you have (at least) two possibilities: you can modify the (old) Car class or you can’t. In the first case you make out with defining a constructor for class Car that takes a CarMaker object:


class Car {

public:

     Car (CarMaker const&);

     // ...
};

In this way you can just call the old constructor getting the parameters from the CarMaker object (remember they are good friends!).

But if you are unable to change the old class then you can cook up some workarounds. For example, by adding a “create” method to CarMaker. It will return a brand new car calling the old constructor (passing it all the required parameters). The Car class no longer needs to be a friend of CarMaker. No matter when you call this method (in case you’ll get a car with “default” values):

Car myCar = CarMaker (year)

   .model (myCarModel)

   .hp (myCarHP)

   .create();

// Ready to hurtle!

Remember this idiom if you get annoyed at positional parameters!

Advertisements
Comments
  1. […] This short post is not about CRTP in general – see, for example, Wikipedia – here I’ll show how to use this pattern for polymorphic method chaining. Briefly: each method returns an object (possibly the current object itself), allowing the calls to be chained together in a single statement (I wrote about a typical use – the named-parameter idiom – here “Learn how to support named parameters in C++“). […]

  2. I seldom leave a response, however i did a few searching and wound up here Learn how to support named parameters in
    C++ | Growing up. And I do have a few questions for you if
    you do not mind. Could it be just me or does it look like a few of these comments appear as if they are left by
    brain dead folks? 😛 And, if you are posting
    at other social sites, I would like to follow anything new you have to
    post. Could you list of all of all your public sites like your Facebook page, twitter feed, or linkedin
    profile?

  3. […] way to emulate named parameters consists in the Named parameter idiom (and this is just another post about). The idea is simple: create a proxy class which houses all the parameters. Optional ones are […]

  4. PapersHelm says:

    This page certainly has all of the info I wanted about this subject and
    didn’t know who to ask.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s