Problem kompilatora C ++ ze strukturą w klasie szablonów

13

Poniższy kod nie kompiluje się z gcc lub 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;
};

Komunikat o błędzie to

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

Błąd jest spowodowany przez foo klasy templat. Podczas pisania <= zamiast <1 również się kompiluje.

Czy podoba Ci się jakaś wskazówka?

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

123tv
źródło
7
Powiedziałbym, że błędy kompilatora, ale msvc jest jedynym, który to akceptuje: - / Demo . Możliwe obejścia b.bar::foolub nawiasy ( (this->b.foo) < 1)
Jarod42

Odpowiedzi:

1

W GCC rozumiem

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

Tak więc kompilator uważa, że footen wiersz odnosi się do klasy foopowyżej i oczekuje argumentu szablonu. To jest podobne do tego, co widzisz.

Kiedy zmienisz na <=, który leksemizuje tokenizator jako pojedynczy token. Następny etap nawet nie widzi a <, więc nie jest przez to zagubiony.

Jeśli zmienisz klasę, aby nie miała takiej samej nazwy jak długo w bar, oznacza to, że nie ma tego problemu. Również @ Jarod42 ma sugestie w swoim komentarzu do twojego pytania (więcej kwalifikacji lub parens).

Kompilatory są pisane etapami, gdzie każdy etap przekłada kod na lepszą reprezentację na następny, a każdy etap może robić coraz bardziej złożone rzeczy z tą reprezentacją.

Na początku kompilator „lekceważy” kod, który zamienia poszczególne znaki w pliku w strumień tokenów - uznałby tę linię za coś w rodzaju

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

A potem dociera do foo. Powinno to chyba wystarczyć

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

Ale wydaje mi się, że kiedy widzi foo, patrzy w przyszłość, widzi <i fakt, który foo<class T>istnieje i próbuje zrobić pojedynczy token, foo< ...ale wtedy nie może go znaleźć >.

To tylko przypuszczenie - może to być etap za leksemem, który próbuje znaleźć nazwy i może łączyć tokeny. W każdym razie wielokrotne użycie foo to oszukuje.

Lou Franco
źródło
Rozumiem twoje wyjaśnienie, ale nie jestem pewien, czy to oznacza, że ​​kompilator powinien się tak zachowywać. Może powinno to być pole jako błąd dla różnych kompilatorów. Czasami nie możesz być świadomy tego, jakie klasy szablonów znajdują się w nagłówku
dołączonej
Myślę, że to błąd, ale nie wiem, co mówi specyfikacja. Posługiwanie się nazwami z nagłówków podmiotów zewnętrznych jest częstym zjawiskiem w C ++ - zwykle można to rozwiązać za pomocą kwalifikacji.
Lou Franco