58 votes

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 fera-t-il l'affaire ?

C'est-à-dire, est-ce que ce qui suit peut fonctionner ?

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

Actuellement, je reçois une erreur :

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

78voto

AlexD Points 7089

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 la fonction correspondante. correspondant. L'ordre d'évaluation des arguments de la fonction n'est pas spécifié. Par conséquent, les paramètres d'une 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

72voto

Baum mit Augen Points 3571

Non, cela ne peut pas fonctionner car l'évaluation des arguments de la fonction n'est pas séquencée. I

Utilisez une surcharge à la place :

void fun(int, int) {}

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

36voto

Richard Hodges Points 1972

Je cherchais une explication logique pour savoir pourquoi ce n'est pas autorisé.

Il s'agit en fait d'une bonne question. La raison en est que le C++ n'impose 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);

Le C++ n'impose pas l'ordre d'évaluation des arguments, vous vous souvenez ?

Alors quelle devrait être la valeur de b ?

f(a) peut être évalué à l'un ou l'autre :

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

Le comportement serait donc indéfini (et même indéfinissable).

En outre, imaginez ce qui pourrait se passer si a et b étaient des objets complexes dont les constructeurs et les opérateurs de copie avaient des effets secondaires.

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

11voto

Marc van Leeuwen Points 803

Vous ne pouvez pas faire ce genre de choses parce que la norme ne le permet pas. Cependant, comme les arguments par défaut ne font que définir de nouvelles surcharges de fonctions, vous pouvez obtenir l'effet désiré 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 interdisant cela est tiède, comme le suggère le langage ("Par conséquent... ne doit pas..."). Ils n'ont tout simplement pas voulu se donner la peine de bien définir cela avec le même effet que ce que ferait la déclaration explicite de la surcharge : s'ils l'avaient voulu, ils auraient pu spécifier que les arguments par défaut sont évalués après ceux explicitement fournis, et de gauche à droite. Cela n'aurait aucune influence sur la règle selon laquelle l'ordre d'évaluation des expressions d'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 la même portée lexicale). D'autre part, si (comme ils l'ont fait) ils préféraient interdire cela, ils auraient pu simplement dire "ne doit pas" sans avoir besoin de se justifier à partir d'une autre règle (mais peut-être avec une note de bas de page explicative).

2voto

R Sahu Points 24027

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

La valeur par défaut d'un argument ne peut pas être un autre argument. Cependant, cela ne signifie pas qu'elle doit être une constante. Elle 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.
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X