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
b.bar::foo
lub nawiasy ((this->b.foo) < 1
)Odpowiedzi:
W GCC rozumiem
Tak więc kompilator uważa, że
foo
ten wiersz odnosi się do klasyfoo
powyż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
A potem dociera do
foo
. Powinno to chyba wystarczyćAle wydaje mi się, że kiedy widzi
foo
, patrzy w przyszłość, widzi<
i fakt, któryfoo<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.
źródło