2016-05-19 5 views
57

C++のデフォルト引数の場合、値は定数である必要がありますか、別の引数ではどうなりますか?C++のデフォルト引数を別の引数で初期化することはできますか?

つまり、次のことができますか?

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

現在、私はエラーを取得しています:

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

+4

@BaummitAugenかなり結論ではないですか? –

+0

@RichardHodgesええ、コンパイラはここのお金にちょうどいいです。 –

+1

私はなぜそれが許可されていないの論理的な説明を探していた。 – user1918858

答えて

78

別の引数はデフォルト値として使用することはできません。標準状態:

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.

と次のサンプルでそれを示しています。関数の引数の評価が配列決定されていないため、動作しないことができる

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

ありません。それは標準では許可されていないので動作しませんが、それは明らかでした。過負荷の代わりに

用途:

void fun(int, int) {} 

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

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

これは実際には良い質問です。その理由は、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がコンストラクタおよびコピー演算子が副作用を持つ複雑なオブジェクトであった場合に、どうなるか考えてみてください。

これらの副作用の順序は未定義です。

+1

いい例... int f(int a = b ++、int b = a ++);私はそれが正当であれば、奇妙なループのためにそれが必要です – Mzn

+4

@Mznは未定義の動作です。 –

11

標準で許可されていないため、このようなことはできません。しかし、デフォルト引数が効果的にちょうどあなたが明示的に、このような過負荷を定義することにより、所望の効果を得ることができ、新しい関数のオーバーロードを定義するので:

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

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

これは、(言語によって提案されたとして、これを禁止する標準は、中途半端であることを示しています」結果的に...してはならない... ")。彼らは明示的なオーバーロード宣言と同じ効果でこれをうまく定義するという手間を惜しまないことを望んでいました。望むならば、明示的に与えられた引数が左から右に評価されることを指定できました。これは、関数呼び出しでの引数式の評価順序が指定されていない(デフォルトの引数はそのような式に対応していないため、完全に分離しており、同じレキシカルスコープではないため)というルールには何の影響も与えません。他方、(彼らがしたように)彼らは、これを禁止することを好むならば、他の何らかの規則から自分自身を正当化する必要がなくても(「たぶん」と説明していたかもしれない)と言っただけかもしれない。

2

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

引数のデフォルト値は別の引数であってはなりません。しかし、それは定数でなければならないというわけではありません。関数呼び出しの戻り値にすることができます。

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. 
} 
関連する問題