Проблема компилятора C ++ со структурой в шаблонном классе

13

Следующий код не компилируется с gcc или 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;
};

Сообщение об ошибке

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

Ошибка вызвана классом templat foo. При записи <= вместо <1 он также компилируется.

Любой намек оценили?

Ссылка CompilerExplorer https://godbolt.org/z/v6Tygo

123tv
источник
7
Я бы сказал, ошибки компилятора, но msvc - единственный, кто принимает это: - / Демо . Возможные обходные пути b.bar::fooили скобки ( (this->b.foo) < 1)
Jarod42

Ответы:

1

В GCC я получаю

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

Таким образом, компилятор считает, что в fooэтой строке относится к классу fooвыше и ожидает аргумент шаблона. Это похоже на то, что вы видите.

Когда вы меняете его на <=, который лексер маркирует как один токен. Следующий этап даже не видит <, поэтому его это не смущает.

Если вы измените класс на имя, отличное от long bar, то у него не будет этой проблемы. Кроме того, у @ Jarod42 есть предложения в его комментарии к вашему вопросу (больше квалификации или параны).

Компиляторы написаны поэтапно, где каждый этап переводит код в лучшее представление для следующего, и каждый этап может делать все более и более сложные вещи с этим представлением.

В начале, компилятор "лексирует" код, который превращает отдельные символы в файле в поток токенов - он будет видеть эту строку как что-то вроде

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

И тогда дело доходит до foo. Вероятно, следует сделать

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

Но мне кажется, что когда он видит foo, он смотрит в будущее, видит <и тот факт, который foo<class T>существует, и он пытается сделать из него один токен, foo< ...но затем он не может найти тот, >чтобы завершить его.

Это всего лишь предположение - это может быть этап мимо лексера, который пытается найти имена и может комбинировать токены. В любом случае, многократное использование foo обманывает его.

Лу Франко
источник
Я понимаю ваше объяснение, но не уверен, означает ли это, что компилятор должен вести себя так. Может быть, это должно быть поле как ошибка для разных компиляторов. Иногда вы не можете знать, какие классы шаблонов находятся в заголовке связанной библиотеки (общие имена, такие как cnt, count, counter ...)
eactor
Я думаю, что это ошибка, но я не знаю, что говорит спецификация. Наличие имен из сторонних заголовков, вызывающих проблемы, является обычным явлением в C ++ - обычно его можно решить с помощью квалификации.
Лу Франко