0

I've got a strange compile error with intel compiler on linux.

So I did some tests with Compiler Explorer.

This code compiles fine on several compilers:

enum class Enum {a, b};

template <int>
struct Base {
    template <Enum a, Enum b> void F(int) {}
};

template <int i>
struct Derived : Base<i> {

    void G() {
        Base<i>::F<Enum::a, Enum::b>(1);
    }
};

int main() {
    Derived<1> D;
}

But with x86-64 gcc 8.1, I get:

<source>: In member function 'void Derived<i>::G()':

<source>:12:36: error: no match for 'operator>' (operand types are 'Enum' and 'int')

         Base<i>::F<Enum::a, Enum::b>(1);

                             ~~~~~~~^~~~

This is a very similar error that what I got with the intel compiler. This example compiles fine on compiler explorer with icc 17 though.

In both cases, this compiles fine if I remove the second template parameter.

What's going on here? What workaround could I use?

ThreeStarProgrammer57
  • 2,906
  • 2
  • 16
  • 24
  • 2
    IIRC you need `Base::template F(1);`. Nice nickname by the way. :P – HolyBlackCat May 31 '18 at 16:33
  • @HolyBlackCat Wow I'll try it, if this works you're my savior ! Why is this not needed on most compilers? And why is this working with 1 template parameter but not with 2?? – ThreeStarProgrammer57 May 31 '18 at 16:38
  • Most compilers? Where else does it work in addition to icc? *"why is this working with 1 template parameter"* That's weird indeed, I have no clue. – HolyBlackCat May 31 '18 at 16:54
  • @HolyBlackCat Well, on compiler explorer it worked with icc / msvc / clang (oops no, not with clang, my bad)... Now I'm tempted to ask a new question on "why is it working with 1 template parameter"... Anyway, thanks a lot, I've wasted 3 hours on this :( – ThreeStarProgrammer57 May 31 '18 at 17:00
  • I smell ICC bug. MSVC compiles it, but it's known to not implement a thing called [two-phase lookup](http://en.cppreference.com/w/cpp/language/unqualified_lookup#Template_definition) (i.e. a bug as well, not sure if the last versions are the same). – HolyBlackCat May 31 '18 at 17:03
  • @HolyBlackCat, well, not knowing why it is needed, this bug feels like a feature for me. I'll have to read the other already answered question answer. – ThreeStarProgrammer57 May 31 '18 at 17:11
  • Since it doesn't seem to be answered in the link, I suggest asking a new question about why it compiles when you only have one parameter. If you don't want to, I'll ask myself. :) – HolyBlackCat May 31 '18 at 17:13
  • @HolyBlackCat Hey I want the precious internet points ;). If I don't have asked in 24 hours, feel free to do it. – ThreeStarProgrammer57 May 31 '18 at 17:18
  • @HolyBlackCat Actually this works with 1 template parameter only if main doesn't call D.G(). Still strange, but probably not overly interesting... – ThreeStarProgrammer57 May 31 '18 at 21:18
  • I think I got it. If there is one parameter, the compiler treats `<` and `>` as comparsion operators and `Base::F` as an identifier (not necessarily a function), and it can't further check the expression for validity before substituting `int i`. If there are two parameters, it's again treated as two comparsion operators, but with comma in between. The left side can't be checked before substitution, but the right one can be, and the compiler is able to tell that it's invalid regardless of `int i`. – HolyBlackCat May 31 '18 at 22:14
  • @HolyBlackCat Wow nice find! But, this seems expose that the first look-up is trying hard to make sense of expressions without enough information. How is this a good thing, why aren't template checked only after instantiation, à la msvc? I understand that it would be non compliant, but why didn't the standard choose to go for the easier to use and to implement way? Dependent names are going to be looked for based on what has been defined so far when the template is instantiated anyway... So why not accept it and do the same for independent names? – ThreeStarProgrammer57 May 31 '18 at 22:44

0 Answers0