可以使用另一个参数初始化C ++默认参数吗?

时间:2016-05-19 22:59:41

标签: c++

对于C ++中的默认参数,值是否需要是常量还是另一个参数呢?

也就是说,以下工作可以吗?

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

目前我收到错误:

  

RateLimiter.h:13:错误:'rateInPermitsPerSecond'未在此范围内声明

5 个答案:

答案 0 :(得分:78)

另一个参数不能用作默认值。标准规定:

  

8.3.6默认参数
...
   9 每次调用函数时都会计算默认参数,且没有相应的参数   参数。函数参数的评估顺序未指定。因此,参数a   函数不应在默认参数中使用,即使它们未被评估。

并用以下示例说明:

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

答案 1 :(得分:72)

不,这不起作用,因为函数参数的评估没有排序。它也不起作用,因为标准不允许它,但我想这很明显。

改为使用重载:

void fun(int, int) {}

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

答案 2 :(得分:36)

  

我正在寻找一个合理解释为什么不允许

这实际上是一个很好的问题。原因是C ++没有强制要求评估参数的顺序。

让我们想象一个稍微复杂的场景:

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

... followed by ...

int a = 1;
f(a);

C ++没有强制要求评估参数的顺序,还记得吗?

那么b的价值应该是什么?

f(a)可评估为:

f(1, 2),或 f(2, 2),取决于参数的评估顺序。

因此行为将是未定义的(甚至是不可定义的)。

此外,考虑当a和b是构造函数和复制操作符具有副作用的复杂对象时可能发生的情况。

这些副作用的顺序是不确定的。

答案 3 :(得分:11)

你不能做那样的事情,因为标准不允许这样做。但是,由于默认参数实际上只是定义了新的函数重载,因此可以通过显式定义这样的重载来获得所需的效果:

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

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

这表明禁止这种情况的标准是半心半意的,正如语言所暗示的那样(“因此......不应......”)。他们只是不想经历使得这个定义得很好的麻烦,其效果与显式重载声明的作用相同:如果需要,他们可以指定默认参数在明确提供的参数之后进行评估,并且从左到右。这对函数调用中参数表达式的求值顺序未指定的规则没有任何影响(因为默认参数不对应于这样的表达式;它们完全是分开的,甚至不在相同的词法范围内)。另一方面,如果(正如他们所做的那样)他们倾向于不允许这样做,他们可能只是说“不应该”,而不需要从其他规则中证明自己(但可能有解释性脚注)。

答案 4 :(得分:2)

  

对于C ++中的默认参数,值是否需要是常量还是另一个参数呢?

参数的默认值不能是另一个参数。但是,这并不意味着它必须是一个常数。它可以是函数调用的返回值。

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.
}