mismo - diferencia entre c y c++ y c#
¿Cómo se diferencia un analizador de C++ entre las comparaciones y las instancias de plantillas? (4)
En C ++, los símbolos ''<'' y ''>'' se usan para comparaciones, así como para significar un argumento de plantilla. Por lo tanto, el fragmento de código
[...] Foo < Bar > [...]
Podría interpretarse como cualquiera de las dos formas siguientes:
- Un objeto de tipo Foo con barra de argumento de plantilla.
- Compara Foo con Bar, luego compara el resultado con lo que venga a continuación
¿Cómo el analizador de un compilador de C ++ decide de manera eficiente entre esas dos posibilidades?
El punto importante a recordar es que la gramática de C ++ no está libre de contexto. Es decir, cuando el analizador ve que Foo < Bar
(en la mayoría de los casos) sabe que Foo
refiere a una definición de plantilla (buscándola en la tabla de símbolos) y, por lo tanto, <
no puede ser una comparación.
Hay casos difíciles, cuando literalmente tienes que guiar el analizador. Por ejemplo, suponga que está escribiendo una plantilla de clase con una función de miembro de plantilla, en la que desea especializarse explícitamente. Es posible que tengas que usar una sintaxis como:
a->template foo<int>();
(en algunos casos, consulte Llamar a la función de plantilla dentro de la clase de plantilla para más detalles)
Además, las comparaciones dentro de los argumentos de las plantillas que no son de tipo deben estar entre paréntesis, es decir:
foo<(A > B)>
no
foo<A > B>
Los inicializadores de miembros de datos no estáticos son más divertidos: http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#325
La mayoría de las respuestas aquí confunden la determinación del significado del símbolo (lo que yo llamo "resolución de nombres") con el análisis (definido de manera restringida como "puede leer la sintaxis del programa").
Puedes hacer estas tareas por separado. .
Lo que esto significa es que puede crear un analizador completamente libre de contexto para C ++ (como lo hace mi empresa, Semantic Designs), y dejar los problemas de decidir cuál es el significado del símbolo para una tarea de seguimiento explícitamente independiente.
Ahora, esa tarea está dirigida por las posibles interpretaciones de sintaxis del código fuente. En nuestros analizadores, estos se capturan como ambigüedades en el análisis.
Lo que hace la resolución de nombres es recopilar información sobre las declaraciones de nombres, y usar esa información para determinar cuál de los análisis ambiguos no tiene sentido, y simplemente eliminarlos. Lo que queda es un solo análisis válido, con una sola interpretación válida.
La maquinaria para lograr la resolución de nombres en la práctica es un gran lío. Pero eso es culpa del comité de C ++, no del analizador o del solucionador de nombres. La eliminación de la ambigüedad con nuestra herramienta en realidad se realiza de manera automática, lo que hace que la parte sea realmente agradable, pero si no mira dentro de nuestras herramientas, no lo apreciaría, pero lo hacemos porque significa que un pequeño equipo de ingeniería fue capaz de construirla.
Vea un ejemplo de resolución de template-vs-less en el análisis más desconcertante de C ++ realizado por nuestro analizador.
Los analizadores de C y C ++ son "sensibles al contexto", en otras palabras, para un token o lexema dado, no se garantiza que sean distintos y tengan un solo significado: depende del contexto dentro del cual se usa el token.
Entonces, la parte del analizador del compilador sabrá (entendiendo "dónde está en la fuente") que está analizando algún tipo de tipo o comparación (esto NO es fácil de saber, por lo que leer la fuente de El compilador C o C ++ competente no es completamente sencillo: hay muchas condiciones y verificación de llamadas de función "es una de estas, si es así, haz otra cosa").
La template
palabras clave ayuda al compilador a comprender lo que está sucediendo, pero en la mayoría de los casos, el compilador simplemente sabe porque <
no tiene sentido en el otro aspecto, y si no tiene sentido en CUALQUIER forma, entonces es un error, Entonces, solo es cuestión de tratar de averiguar lo que el programador podría haber deseado, y esta es una de las razones por las que, a veces, un simple error, como la falta de una template
o una template
puede desviar a todo el análisis y dar lugar a cientos o miles. de errores [aunque los compiladores sanos se detienen después de un número razonable para no llenar todo el universo con mensajes de error]
Si se sabe que Foo
es un nombre de plantilla (p. Ej., Una template <...> Foo ...
declaración está dentro del alcance, o si el compilador ve una secuencia de template Foo
), entonces Foo < Bar
no puede ser una comparación. Debe ser el comienzo de una instanciación de plantilla (o como se llame Foo < Bar >
esta semana).
Si Foo
no es un nombre de plantilla, entonces Foo < Bar
es una comparación.
En la mayoría de los casos, se sabe qué es Foo
, porque los identificadores generalmente tienen que ser declarados antes de su uso, por lo que no hay problema para decidir de una u otra forma. Sin embargo, hay una excepción: analizar el código de la plantilla. Si Foo<Bar>
está dentro de una plantilla, y el significado de Foo
depende de un parámetro de plantilla, entonces no se sabe si Foo
es una plantilla o no. El estándar de idioma indica que debe tratarse como una no plantilla a menos que esté precedido por la template
palabras clave.
El analizador podría implementar esto devolviendo el contexto al lexer. El lexer reconoce a Foo
como diferentes tipos de tokens, dependiendo del contexto proporcionado por el analizador.