Problema no compilador C ++ com struct na classe de modelo

13

O código a seguir não compila com gcc ou 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;
};

Mensagem de erro é

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

O erro é causado pela classe templat foo. Ao escrever <= em vez de <1, ele também compila.

Alguma dica apreciada?

Link do CompilerExplorer https://godbolt.org/z/v6Tygo

123tv
fonte
7
Eu diria que os erros do compilador, mas o msvc é o único a aceitá-lo: - / Demo . Possível b.bar::foo(this->b.foo) < 1
solução alternativa

Respostas:

1

No GCC, recebo

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

Portanto, o compilador pensa que a foolinha nessa linha se refere à classe fooacima e espera um argumento de modelo. Isso é semelhante ao que você está vendo.

Quando você altera para <=, que é tokenizado pelo lexer como um único token. O próximo estágio nem vê um <, por isso não é confundido com ele.

Se você alterar a classe para não ter o mesmo nome que o long in bar, ele não terá esse problema. Além disso, @ Jarod42 tem sugestões no seu comentário à sua pergunta (mais qualificação ou parens).

Os compiladores são escritos em estágios, onde cada estágio converte o código em uma melhor representação para o próximo, e cada estágio pode fazer coisas cada vez mais complexas com essa representação.

No início, o compilador "anexa" o código, que transforma os caracteres individuais no arquivo em um fluxo de tokens - veria essa linha como algo como

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

E então chega ao foo. Provavelmente deveria fazer

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

Mas, parece-me que quando vê foo, olha para frente, vê o <fato que foo<class T>existe e tenta criar um único token, foo< ...mas não consegue encontrar o >que o completa.

Isso é apenas um palpite - pode ser um estágio passado do lexer que tenta encontrar nomes e pode combinar tokens. De qualquer forma, os múltiplos usos do foo estão enganando-o.

Lou Franco
fonte
Entendo sua explicação, mas não tenho certeza se isso significa que o compilador deve se comportar dessa maneira. Talvez esse campo deva ser um bug para os diferentes compiladores. Às vezes, você não pode estar ciente de quais classes de modelo estão dentro de um cabeçalho de biblioteca vinculada (nomes comuns como cnt, count, counter ...)
eactor
Eu acho que é um bug, mas não sei o que as especificações dizem. Ter nomes de cabeçalhos de terceiros causando problemas é uma ocorrência comum em C ++ - geralmente você pode resolver com qualificação.
Lou Franco