Can a C++ default argument be initialized with another argument?

C++

C++ Problem Overview


For a default argument in C++, does the value need to be a constant or will another argument do?

That is, can the following work?

RateLimiter(unsigned double rateInPermitsPerSecond, 
            unsigned int maxAccumulatedPermits = rateInPermitsPerSecond);

Currently I am getting an error:

> RateLimiter.h:13: error: ‘rateInPermitsPerSecond’ was not declared in this scope

C++ Solutions


Solution 1 - C++

Another argument cannot be used as the default value. The standard states:

> 8.3.6 Default arguments
...
9 A default argument is evaluated each time the function is called with no argument for the corresponding parameter. The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in a default argument, even if they are not evaluated.

and illustrates it with the following sample:

int f(int a, int b = a); // error: parameter a
                         // used as default argument

Solution 2 - C++

No, that cannot work because the evaluation of function arguments is not sequenced. It also does not work because the standard does not allow it, but I guess that was obvious.

Use an overload instead:

void fun(int, int) {}

void fun(int i) {
    fun(i, i);
}

Solution 3 - C++

> I was looking for an logical explanation for why it is not allowed

This is actually a good question. The reason is that C++ does not mandate the order of evaluation of arguments.

So let's imagine a slightly more complex scenario:

int f(int a, int b = ++a);

... followed by ...

int a = 1;
f(a);

C++ does not mandate the order of evaluation of arguments, remember?

So what should be the value of b?

f(a) can evaluate to either:

f(1, 2), or f(2, 2), depending on the order of evaluation of the arguments.

Thus the behaviour would be undefined (and even undefinable).

Further, consider what might happen when a and b were complex objects whose constructors and copy operators had side-effects.

The order of those side-effects would be undefined.

Solution 4 - C++

You cannot do things like that because the standard does not allow it. However since default arguments effectively just define new function overloads, you can get the desired effect by explicitly defining such an overload:

void RateLimiter(unsigned int rateInPermitsPerSecond, 
                 unsigned int maxAccumulatedPermits);

inline void RateLimiter(unsigned int rateInPermitsPerSecond)
{ return RateLimiter(rateInPermitsPerSecond,rateInPermitsPerSecond); }

This shows that the standard forbidding this is half-hearted, as suggested by the language ("Consequently... shall not..."). They just did not want to go through the hassle of making this well defined with the same effect as what the explicit overload declaration would do: if desired, they could have specified that defaulted arguments are evaluated after explicitly provided ones, and from left to right. This would not have any influence on the rule that the evaluation order of argument expressions in a function call is unspecified (because default arguments do not correspond to such expressions; they are entirely separate and not even in the same lexical scope). On the other hand if (as they did) they preferred to disallow this, they could have just said "shall not" without need to justify themselves from some other rule (but maybe with explanatory footnote).

Solution 5 - C++

>For a default argument in C++, does the value need to be a constant or will another argument do?

The default value of an argument cannot be another argument. However, that does not mean it has to be a constant. It can be the return value of a function call.

int getNextDefaultID()
{
   static int id = 0;
   return ++id;
}

struct Foo
{
   Foo(int data, int id = getNextDefaultID()) : data_(data), id_(id) {}
   int data_;
   int id_;
};

int main()
{
    Foo f1(10);      // Gets the next default ID.
    Foo f2(20, 999); // ID is specified.
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1918858View Question on Stackoverflow
Solution 1 - C++AlexDView Answer on Stackoverflow
Solution 2 - C++Baum mit AugenView Answer on Stackoverflow
Solution 3 - C++Richard HodgesView Answer on Stackoverflow
Solution 4 - C++Marc van LeeuwenView Answer on Stackoverflow
Solution 5 - C++R SahuView Answer on Stackoverflow