web-dev-qa-db-fra.com

Gcc ou clang ont-ils raison sur ce comportement?

J'ai un petit programme de jouets:

static int value = 0;

int function(int &value=value) {
    return value;
}

int main() {
    function();
}

Compilation avec g ++ 7.2:

g ++ -std = c ++ 11 -Wall -Wextra test.cc -o test

Aucun problème.

Compiler avec clang ++ - 3.9:

clang ++ - 3,9 -std = c ++ 11 -Mur -Wextra test.cc -o test

test.cc:3:25: error: default argument references parameter 'value'
int function(int &value=value) {
                        ^~~~~
test.cc:8:5: error: no matching function for call to 'function'
    function();
    ^~~~~~~~
test.cc:3:5: note: candidate function not viable: requires single argument 'value', but no arguments were provided
int function(int &value=value) {
    ^
2 errors generated.

Kaboom. Qui a raison?

38
gct

Je pense que clang est correct. De basic.scope.pdecl :

Le point de déclaration d'un nom est immédiatement après son déclarateur complet (Clause [dcl.decl] ) et avant son initialiseur (le cas échéant), sauf comme indiqué ci-dessous. [ Exemple:

int x = 12;{ int x = x; }

Ici, le deuxième x est initialisé avec sa propre valeur (indéterminée). - fin exemple]

Aussi, depuis dcl.fct.default :

Les arguments par défaut sont évalués à chaque appel de la fonction. L'ordre d'évaluation des arguments de fonction n'est pas spécifié. Par conséquent, les paramètres d'une fonction ne doivent pas être utilisés dans un argument par défaut, même s'ils ne sont pas évalués. Les paramètres d'une fonction déclarée avant un argument par défaut sont dans la portée et peuvent masquer l'espace de noms et les noms des membres de classe

32
R Sahu

Étant donné que l'OP a marqué la question en tant que c ++ 11, j'ai vérifié cette version de la norme et dans la sous-clause 11 de [basic.lookup.unqual] , il indique explicitement que:

Lors de la recherche d'un nom utilisé comme argument par défaut (8.3.6) dans une clause de déclaration de paramètre de fonction ou utilisé dans l'expression d'un initialiseur de mémoire pour un constructeur (12.6.2), les noms des paramètres de fonction sont visibles et masquer les noms des entités déclarées dans les étendues de bloc, de classe ou d'espace de noms contenant la déclaration de fonction.

Ainsi, le bruit est correct.

18
Johan

Clang a raison ici. Tout d'abord un étendue du paramètre de la fonction est défini comme:

Un paramètre de fonction (dont un apparaît dans un lambda-declarator) ou une variable prédéfinie locale de fonction ([dcl.fct.def]) a une portée de paramètre de fonction. La portée potentielle d'un paramètre ou d'une variable prédéfinie locale de fonction commence à son point de déclaration. [...]

et le point de déclaration est défini comme

Le point de déclaration d'un nom est immédiatement après son déclarateur complet et avant son initialiseur (le cas échéant), sauf comme indiqué ci-dessous. [ Exemple:

unsigned char x = 12;
{ unsigned char x = x; }

Ici, le deuxième x est initialisé avec sa propre valeur (indéterminée). - fin exemple]

Donc value devrait être le value que vous venez de déclarer et non celui de l'espace global

8
NathanOliver