How can I clearly indicate which arguments I pass and which by default remain?

Asked for this: The default argument in C ++

Let's say that I have such a function: void f(int p1=1, int p2=2, int p3=3, int p4=4);

And I want to call it using only some of the arguments - the rest will be by default.

Something like this will work:

 template<bool P1=true, bool P2=true, bool P3=true, bool P4=true> void f(int p1=1, int p2=2, int p3=3, int p4=4); // specialize: template<> void f<false, true, false, false>(int p1) { f(1, p1); } template<> void f<false, true, true, false>(int p1, int p2) { f(1, p1, p2); } // ... and so on. // Would need a specialization for each combination of arguments // which is very tedious and error-prone // Use: f<false, true, false, false>(5); // passes 5 as p2 argument 

But this requires too much code.

Is there a better way to do this?

+8
c ++ c ++ 11 function-overloading default-arguments
source share
4 answers

Use the Named Parameter Identifier (β†’ FAQ ) link.

The Boost.Parameters library (β†’ link ) can also solve this problem, but the verbosity and significantly reduced clarity are paid by the code. It also does not cope with the processing of constructors. And that requires a Boost library, of course.

Cheers and hth.,

+11
source share

Take a look at the Boost.Parameter library.

It implements named parameters in C ++. Example:

 #include <boost/parameter/name.hpp> #include <boost/parameter/preprocessor.hpp> #include <iostream> //Define BOOST_PARAMETER_NAME(p1) BOOST_PARAMETER_NAME(p2) BOOST_PARAMETER_NAME(p3) BOOST_PARAMETER_NAME(p4) BOOST_PARAMETER_FUNCTION( (void), f, tag, (optional (p1, *, 1) (p2, *, 2) (p3, *, 3) (p4, *, 4))) { std::cout << "p1: " << p1 << ", p2: " << p2 << ", p3: " << p3 << ", p4: " << p4 << "\n"; } //Use int main() { //Prints "p1: 1, p2: 5, p3: 3, p4: 4" f(_p2=5); } 
+7
source share

Despite the fact that Boost.Parameters are funny, it suffers (unfortunately) for a number of problems, including a collision with a placeholder (and the need to debug fancy preprocessors / template errors):

 BOOST_PARAMETER_NAME(p1) 

Creates a placeholder _p1 , which you then use later. If you have two different headers declaring the same placeholder, you get a conflict. Not fun.

There is a much simpler (both conceptually and practically) answer based on the Builder Template, which is the Idiom Named Parameter .

Instead of specifying such a function:

 void f(int a, int b, int c = 10, int d = 20); 

You specify the structure on which you will override operator() :

  • the constructor is used to request required arguments (not strictly in the Idiom of Named Parameters, but no one said you need to follow it blindly), and default values ​​are set for optional
  • each optional parameter is assigned a setter

As a rule, it is combined with Chaining, which means that setters return a link to the current object, so that calls can be chained on one line.

 class f { public: // Take mandatory arguments, set default values f(int a, int b): _a(a), _b(b), _c(10), _d(20) {} // Define setters for optional arguments // Remember the Chaining idiom f& c(int v) { _c = v; return *this; } f& d(int v) { _d = v; return *this; } // Finally define the invocation function void operator()() const; private: int _a; int _b; int _c; int _d; }; // class f 

Call:

 f(/*a=*/1, /*b=*/2).c(3)(); // the last () being to actually invoke the function 

I saw an option, introducing the required arguments as parameters to operator() , this avoids arguments as attributes, but the syntax is a bit weirder:

 f().c(3)(/*a=*/1, /*b=*/2); 

As soon as the compiler introduced all the calls to the constructor and setter (which is why they are defined here, but operator() not), it should lead to the same efficient code as compared to the β€œregular” function call.

+4
source share

This is actually not the answer, but ...

In the C ++ Template Metaprogramming by David Abrahams and Alexei Gurtova (published in 2004!), The authors talk about this:

When writing this book, we revised the interface used to support function parameters. By experimenting a bit, we found that it can be provided with perfect syntax using keyword objects with overloaded assignment operators:

 f(slew = .799, name = "z"); 

Then they say:

It was not necessary to go into details of the implementation of this name; here is the library of parameters; Its straightforward enough that we suggest that you try to implement it yourself as an exercise.

This was in the context of template metaprogramming and Boost :: MPL. I'm not too sure how their implementation of "straighforward" will be jive with default options, but I assume that it will be transparent.

+2
source share

All Articles