Un argument par défaut C ++ peut-il être initialisé avec un autre argument?

Pour un argument par défaut en C ++, la valeur doit-elle être une constante ou un autre argument le fera-t-il?

C’est-à-dire, le suivant peut-il fonctionner?

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

Actuellement, je reçois une erreur:

RateLimiter.h Erreur: ‘rateInPermitsPerSecond’ n’a pas été déclaré dans cette scope

Un autre argument ne peut pas être utilisé comme valeur par défaut. La norme stipule:

8.3.6 Arguments par défaut

9 Un argument par défaut est évalué chaque fois que la fonction est appelée sans argument pour le paramètre correspondant. L’ordre d’évaluation des arguments de fonction n’est pas spécifié. Par conséquent, les parameters d’une fonction ne doivent pas être utilisés dans un argument par défaut, même s’ils ne sont pas évalués.

et l’illustre avec l’exemple suivant:

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

Non, cela ne peut pas fonctionner car l’évaluation des arguments de fonction n’est pas séquencée. Cela ne fonctionne pas non plus parce que la norme ne le permet pas, mais je suppose que c’était évident.

Utilisez plutôt une surcharge:

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

Je cherchais une explication logique pour expliquer pourquoi ce n’est pas autorisé

C’est en fait une bonne question. La raison en est que C ++ ne commande pas l’ordre d’évaluation des arguments.

Imaginons donc un scénario un peu plus complexe:

 int f(int a, int b = ++a); ... followed by ... int a = 1; f(a); 

C ++ ne commande pas l’ordre d’évaluation des arguments, souvenez-vous?

Alors, quelle devrait être la valeur de b?

f(a) peut évaluer soit:

f(1, 2) ou f(2, 2) , en fonction de l’ordre d’évaluation des arguments.

Ainsi, le comportement serait indéfini (et même indéfinissable).

De plus, considérez ce qui pourrait arriver lorsque a et b étaient des objects complexes dont les constructeurs et les opérateurs de copie avaient des effets secondaires.

L’ordre de ces effets secondaires serait indéfini.

Vous ne pouvez pas faire des choses comme ça parce que la norme ne le permet pas. Cependant, comme les arguments par défaut définissent simplement de nouvelles surcharges de fonctions, vous pouvez obtenir l’effet souhaité en définissant explicitement une telle surcharge:

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

Cela montre que la norme qui l’interdit est timide, comme le suggère la langue (“Par conséquent … ne doit pas …”). Ils ne voulaient tout simplement pas se tracasser pour que cela soit bien défini avec le même effet que la déclaration de surcharge explicite: s’ils le souhaitaient, ils auraient pu spécifier que les arguments par défaut sont évalués après ceux fournis explicitement et de gauche à droite. . Cela n’aurait aucune influence sur la règle selon laquelle l’ordre d’évaluation des expressions des arguments dans un appel de fonction n’est pas spécifié (parce que les arguments par défaut ne correspondent pas à de telles expressions; ils sont entièrement séparés et ne sont même pas dans le même champ lexical). D’un autre côté, si (comme ils l’ont fait) ils ont préféré refuser cela, ils auraient pu simplement dire “ne pas” sans avoir besoin de se justifier d’une autre règle (mais peut-être avec une note explicative).

Pour un argument par défaut en C ++, la valeur doit-elle être une constante ou un autre argument le fera-t-il?

La valeur par défaut d’un argument ne peut pas être un autre argument. Cependant, cela ne signifie pas que ce doit être une constante. Ce peut être la valeur de retour d’un appel de fonction.

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