¿GCC o Clang son correctos acerca de que el nombre de un parámetro de función está dentro del alcance en su propio argumento predeterminado?

4 minutos de lectura

avatar de usuario
gct

Tengo un pequeño programa de juguetes:

static int value = 0;

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

int main() {
    function();
}

Compilando con g++ 7.2:

g++ -std=c++11 -Muro -Wextra prueba.cc -o prueba

No hay problema.

Compilando con clang++-3.9:

clang++-3.9 -std=c++11 -Wall -Wextra test.cc -o prueba

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.

Kabum. ¿Quién tiene razón?

  • int function(int &value=value) me parece muy raro. cambiaría eso por int function(int &value = ::value) por lo que se refiere al mundo value en lugar de que la referencia esté ligada a sí misma.

    – Eljay

    13 de febrero de 2018 a las 16:45

  • @Eljay gcc lo une a lo global value con int& value = valuepero creo que está mal según el estándar actual.

    – Holt

    13 de febrero de 2018 a las 16:46

  • solo curiosidad: cuando ejecuta el gcc, ¿cuál es el valor del valor local? (ohh dios, esa pregunta ha salido mal)…

    – Mono del Reino Unido

    13 de febrero de 2018 a las 16:46

  • A juzgar por el hecho de que puedes usar decltype(param) en el argumento predeterminado, diría que el nombre del parámetro está dentro del alcance y GCC es incorrecto, pero esa no es una base muy sólida.

    – chris

    13 de febrero de 2018 a las 16:49

  • @UKMonkey Aparentemente es el valor real de ::valuees decir, la referencia no se vincula a sí misma.

    – Quintín

    13 de febrero de 2018 a las 16:50

avatar de usuario
R Sahú

Creo que clang es correcto. De basic.scope.pdecl:

El punto de declaración de un nombre es inmediatamente después de su declarador completo (Cláusula [dcl.decl]) y antes de su inicializador (si lo hay), excepto como se indica a continuación. [ Example:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

También, desde dcl.fct.default:

Los argumentos predeterminados se evalúan cada vez que se llama a la función. El orden de evaluación de los argumentos de función no está especificado. En consecuencia, los parámetros de una función no se utilizarán en un argumento predeterminado, incluso si no se evalúan. Los parámetros de una función declarada antes de un argumento predeterminado están dentro del alcance y pueden ocultar el espacio de nombres y los nombres de los miembros de la clase.

  • Esa parece ser la respuesta, sorprendido de que gcc se lo haya perdido.

    – gct

    13 de febrero de 2018 a las 16:57

  • @SeanMcAllister, sí, es sorprendente que g ++ se pierda este.

    – R Sahu

    13 de febrero de 2018 a las 16:58

  • Pero esta cita no prohíbe que el argumento predeterminado haga referencia al parámetro de función como se queja de clang.

    – usuario7860670

    13 de febrero de 2018 a las 17:00


  • @VTT Éste lo hace.

    – Holt

    13 de febrero de 2018 a las 17:07

  • El único caso de uso sería tomar la dirección del parámetro para definir su propio valor. ¿Quién lo hizo? ¿Por qué exponer al codificador a errores para un caso tan inútil? El estándar es incorrecto, por lo que gcc tiene razón al estar equivocado.

    – oliva

    13 de febrero de 2018 a las 20:54

avatar de usuario
johan

Dado que el OP etiquetó la pregunta como c ++ 11, verifiqué esa versión del estándar y en [basic.lookup.unqual] la subcláusula 11 establece explícitamente que:

Durante la búsqueda de un nombre utilizado como argumento predeterminado (8.3.6) en una cláusula de declaración de parámetro de función o utilizado en la expresión de un inicializador de mem para un constructor (12.6.2), los nombres de los parámetros de función son visibles y ocultar los nombres de las entidades declaradas en los ámbitos de bloque, clase o espacio de nombres que contienen la declaración de la función.

Por lo tanto, clang es correcto.

avatar de usuario
NathanOliver

Clang es correcto aquí. Primero un alcance del parámetro de la función Se define como:

Un parámetro de función (incluido uno que aparece en un declarador lambda) o una variable predefinida local de función ([dcl.fct.def]) tiene ámbito de parámetro de función. El alcance potencial de una variable predefinida local de función o parámetro comienza en su punto de declaración.[…]

y el punto de declaración Se define como

El punto de declaración de un nombre es inmediatamente después de su declarador completo y antes de su inicializador (si lo hay), excepto como se indica a continuación. [ Example:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

Asi que value debería ser el value acabas de declarar y no el del espacio global

¿Ha sido útil esta solución?