Problema del compilador de C ++ con estructura en clase de plantilla

13

El siguiente código no se compila con gcc o clang.

template<class T>
class foo{};

template<class T>
class template_class_with_struct
{
    void my_method() {
        if(this->b.foo < 1);
    };

    struct bar
    {
        long foo;
    } b;
};

Mensaje de error es

error: type/value mismatch at argument 1 in template parameter list for 'template<class T> class foo'    
    8 |         if(this->b.foo < 1);

El error es causado por templat class foo. Al escribir <= en lugar de <1, también se compila.

¿Alguna pista apreciada?

CompilerExplorer link https://godbolt.org/z/v6Tygo

123tv
fuente
77
Diría errores del compilador, pero msvc es el único que lo acepta: - / Demo . Posibles soluciones b.bar::fooo paréntesis ( (this->b.foo) < 1)
Jarod42

Respuestas:

1

En GCC, me sale

so.cpp:8:27: error: expected '>'
    if(this->b.foo < 1) 
                      ^

Entonces, el compilador piensa que fooen esa línea se refiere a la clase fooanterior y espera un argumento de plantilla. Esto es similar a lo que estás viendo.

Cuando lo cambia a <=, que el lexer tokeniza como un token único. La siguiente etapa ni siquiera ve a <, por lo que no se confunde con ella.

Si cambia la clase para que no tenga el mismo nombre que la entrada larga bar, entonces no tiene este problema. Además, @ Jarod42 tiene sugerencias en su comentario a su pregunta (más calificación o parens).

Los compiladores se escriben en etapas, donde cada etapa traduce el código a una mejor representación para la siguiente, y cada etapa puede hacer cosas cada vez más complejas con esa representación.

Al principio, el compilador "lexes" el código, que convierte los caracteres individuales en el archivo en una secuencia de tokens; vería esta línea como algo así como

// if(this->b.foo < 1) 
- keyword(if)
- left-paren
- keyword(this)
- operator(->)
- name(b)
- operator(.)

Y luego llega a la foo. Probablemente debería hacer

- name(foo)
- operator(<)
- number(1)
- right-paren

Pero, me parece que cuando ve foo, mira hacia adelante, ve el <hecho y el hecho de que foo<class T>existe e intenta hacer una sola ficha foo< ...pero luego no puede encontrar la >para completarla.

Esto es solo una suposición: podría ser una etapa más allá del lexer que intenta encontrar nombres y puede combinar tokens. En cualquier caso, los múltiples usos de foo lo están engañando.

Lou Franco
fuente
Entiendo su explicación, pero no estoy seguro si significa que el compilador debería comportarse de esa manera. Tal vez esto debería ser un campo como error para los diferentes compiladores. A veces no puede saber qué clases de plantilla están dentro de un encabezado de biblioteca vinculado (nombres comunes como cnt, count, counter ...)
eactor
Creo que es un error, pero no sé qué dice la especificación. Tener nombres de encabezados de terceros que causan problemas es una ocurrencia común en C ++; por lo general, puede resolver con calificación.
Lou Franco