7

I want to achieve this:

- second parameter by default set to first argument

Something like:

int foo (int a, int b = a);

But how to do that?

Thanks a lot!

0

4 Answers 4

17

This is forbidden by:

8.3.6 Default arguments [dcl.fct.default]

9) Default arguments are evaluated each time the function is called. The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in default argument expressions, even if they are not evaluated. Parameters of a function declared before a default argument expression are in scope and can hide namespace and class member names. [ Example:

int a;

int f(int a , int b = a); / / error: parameter a

/ / used as default argument

typedef int I;

int g( float I , int b = I (2)); / / error: parameter I found

int h(int a , int b = sizeof (a )); / / error, parameter a used

/ / in default argument

—end example ]

An alternative is overloading:

int foo(int a, int b);

int foo(int a)
{
   return foo(a,a);
}
Sign up to request clarification or add additional context in comments.

5 Comments

AFAIK parameter default values could be anything which can be evaluated during calling this function, it is not limited to compile time constants. Like: int g = 1; int f(int a = g); int main () { f(); g = 2; f(); };...
@PiotrNycz you're right, but I managed to find the exact quote that forbids this. Thanks for pointing it out!
And this is real reason: "The order of evaluation of function arguments is unspecified." to forbid this.
What if the function is constructor? How to merge them efficiently? like A (int _a) : a (_a), b(_a) {...} and A (int _a, int _b) : a(_a), b(_b) {...}. Thank you so much.
@user180574 ah - in C++11 there's delegate constructors. Pre-C++11, there's no clean way (but you can use an init() function, although that's frowned upon in some cases).
2

I recommend using overloading for this particular task as Luchian Grigore suggested, but common practice would be to reserve some value to say "this is default". For example

int foo( int a, int b = -1)
{
    if( b == -1){
       b = a;
    }
}

Using object (not scalar values) this could be really nicely implemented (by creating new delivered class reserved to represent default value), but with int you have to do this.

Note that you have to be 100% sure that b cannot get value -1 (or whatever your reserved value is).

4 Comments

+1 for common practice hint, however it's very hard to have meaningful semantics using int (-1 and 0 could be good default values, depending on the set of accepted values i.e. if there is a test for respectively b >= 0 or b > 0.
@AlbertoMoriconi you're right, sometimes MAX_UNSIGNED_INT+1 may also be good call, but this is definitely something that is situation specific and you cannot write an universal solution.
If you want to default a value to "not there" why not use boost::optional?
@MarkB never really worked with that... if you have some resources edit my answer or post new one. I'd glad to learn a new thing or two.
2

The reason this is disallowed has already been addressed, but another solution along the lines of @Vyktor's is to use boost::optional instead of magic numbers (This has pros and cons compared to creating an overload):

int foo(int a, boost::optional<int> b = boost::none)
{
    if(!b) b = a;
}

1 Comment

I'm not sure, but wouldn't boost::bind also offer some usable tricks for this ?
0

This is a little funny answer - but works:

#define TWO_FROM_ONE(a) (a),(a)

f(TWO_FROM_ONE(12));

One disadvantage is that this will call some function twice (a known macro drawback):

f(TWO_FROM_ONE(sin(123 / PI)));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.