Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ compiler issue with struct in template class

The following code does not compile with gcc or 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 message is

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

The error is caused by templat class foo. When writing <= instead of < 1 it also compiles.

Any hint appreciated?

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

like image 932
123tv Avatar asked Feb 06 '20 12:02

123tv


Video Answer


1 Answers

In GCC, I get

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

So, the compiler thinks that the foo on that line refers to the class foo above and is expecting a template argument. This is similar to what you are seeing.

When you change it to <=, which is tokenized by the lexer as a single token. The next stage does not even see a <, so it is not confused by it.

If you change the class to not have the same name as the long in bar, then it doesn't have this issue. Also, @Jarod42 has suggestions in his comment to your question (more qualification or parens).

Compilers are written in stages, where each stage translates the code to a better representation for the next, and each stage can do more and more complex things with that representation.

At the start, the compiler "lexes" the code, which turns the individual characters in the file into a stream of tokens -- it would see this line as something like

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

And then it gets to the foo. It should probably do

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

But, it looks to me like when it sees foo, it looks ahead, sees the < and the fact that foo<class T> exists and it tries to make a single token out of foo< ... but then it can't find the > to complete it.

This is just a guess -- it could be a stage past the lexer that tries to find names and can combine tokens. In any case, the multiple uses of foo is tricking it.

like image 98
Lou Franco Avatar answered Oct 16 '22 23:10

Lou Franco