1

UPDATE 2

Why is this marked a duplicate? Where and why do I have to put the “template” and “typename” keywords? doesn't answer this question. The behavior described here isn't mentioned there anywhere (you won't find a single remark about the expected behavior of auto there).

This is not a duplicate, especially since there's a conflicting behavior in different compilers.


UPDATE

Much like GCC, clang also fails to compile:

17 : error: expected expression
return p->is<true>();
^

However, on MSVC the code with the auto detection is compiling successfully.

Clearly, there's a compiler bug somewhere.


Live example

Consider the following class:

struct A {
    template<bool>
    bool is() const {
        return true;
    }

    template<bool>
    static A* get() {
        static A a;
        return &a;
    }
};

If a template function, such as

template<bool cond>
bool foo() {
    auto p = A::get<cond>();
    return p->is<true>();
}

tries to call A::is<bool>, it fails miserably:

main.cpp: In function 'bool foo()':
main.cpp:17:24: error: expected primary-expression before ')' token
     return p->is<true>();
                        ^
main.cpp: In instantiation of 'bool foo() [with bool cond = true]':
main.cpp:21:22:   required from here
main.cpp:17:17: error: invalid operands of types '<unresolved overloaded function type>' and 'bool' to binary 'operator<'
     return p->is<true>();
                 ^

however, if only we replace auto with the explicit type (A*):

template<bool cond>
bool foo() {
    A* p = A::get<cond>();
    return p->is<true>();
}

it works.

What is the reason for this?

Community
  • 1
  • 1
Avidan Borisov
  • 3,235
  • 4
  • 24
  • 27
  • 3
    ...and you should never claim that you have found a compiler bug unless you have really really good reasons to say so. – Petr Nov 03 '15 at 13:28
  • @Petr Why? Compiler bugs really aren't that uncommon you know. I have encountered countless of them. This is suspicious behavior that isn't consistent across different compilers, so I don't see why should I have a *really really good reason* just to **ask** whether this could be a compiler bug. – Avidan Borisov Nov 03 '15 at 14:32
  • 2
    And I guess you know that much more common are people claiming they found a compiler bug while in fact they just did not understand the standard properly. Moreover, it is just a sign of politeness not to say somebody else is wrong, unless you are absolutely absolutely sure. See [this section](http://www.catb.org/esr/faqs/smart-questions.html#idp59344752) of "How To Ask Questions The Smart Way" by E.S. Raymond. – Petr Nov 03 '15 at 14:40
  • Reopened. All required information is still in [this question](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) and its accepted answer, as well as in the answer by @Petr here. – n. m. could be an AI Nov 03 '15 at 14:52
  • @Petr Notice the title is phrased as a question (see `possible` and `?`). I did not *claim* to find a bug, I was *asking* whether this is possibly a bug. I came to SO asking this after I did my research on the topic and could not determine whether this is the expected behavior myself. That's not being rude, that's being curious. Why is it that SO users are so eager to discourage asking questions? – Avidan Borisov Nov 03 '15 at 14:54
  • @n.m., FWIW, personally I found the fact that `auto` makes an expression type-dependend not that obvious an not covered by the duplicate candidate answer, so I do not think that this is exactly a duplicate. Still I did not vote for reopen either :) – Petr Nov 03 '15 at 15:00
  • @Petr this was my reason for reopening, yes ;) – n. m. could be an AI Nov 03 '15 at 15:19
  • 1
    @Petr There's definitely a compiler bug here (in MSVC). – n. m. could be an AI Nov 03 '15 at 15:20
  • @n.m., yes, it seems so (and yes, I have even checked with the standard that diagnostics seems to be required in this case). However, in the original version of the question (to which most of my comments are), the OP was obviously assuming that _gcc_ has a bug. – Petr Nov 03 '15 at 17:10
  • 1
    @Petr the bug is well-known to language-lawyer-heads (MSVC fails to implement two-phase lookup) but most programmers don't seem to know about it. – n. m. could be an AI Nov 03 '15 at 17:24
  • "you won't find a single remark about the expected behavior of auto there". Please describe what you would like to find described in my article on the duplicated question/answer. Why is it unclear that "p" in your example depends on "cond", given that p's initializer determines p's type and the initializer depends on "cond"? I'm always looking for ways to improve the article. – Johannes Schaub - litb Nov 07 '15 at 14:36

1 Answers1

9

You need to write

return p->template is<true>();

because the compiler does not know initially that is is a template.


Some more deep explanation. With

A* p = A::get<cond>();
return p->is<true>();

the compiler knows even when it is parsing the code that p is of type A* and therefore it sees that p->is is a template.

With

auto p = A::get<cond>();
return p->is<true>();

the compiler does not initially know what type p will be. It will know this only after it has instantiated A::get<cond>, and this will happen only when foo is instantiated. So it does not know that p->is is a template. (And it may easily be not a template is you had specialized version of A for, say, true template parameter.)

Further reading: Where and why do I have to put the "template" and "typename" keywords?


Quote from the Standard [14.2.4]:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

I think this clearly explains that what is observed is correct behavior. Without auto, the type of p is not type-dependent. With auto, is becomes type-dependent.

Community
  • 1
  • 1
Petr
  • 9,812
  • 1
  • 28
  • 52
  • 1
    Why? why does it know `is` is a template when operating on the explicit type versus `auto`? I'm not asking for ways to make this work, I'm looking for reasons (preferably quotes from the standard). – Avidan Borisov Nov 03 '15 at 13:33
  • @Avidanborisov, have you seen the edit (which added the part after the horizontal rule)? – Petr Nov 03 '15 at 13:34
  • 1
    I have now, but it doesn't answer the question. Your speculation why the compiler fails to detect `is` is a template is nice, but I'm looking for definite answers: is this the actual *expected* standard-conforming behavior? – Avidan Borisov Nov 03 '15 at 13:40
  • @Avidanborisov, ok, I think I found a relevant quotation from the Standard (actually it is references in the linked answer) – Petr Nov 03 '15 at 13:47
  • please see the update to the question – Avidan Borisov Nov 03 '15 at 14:32
  • @Avidanborisov, what in particular you want me to see? MSVS is notorious for being non-standard-conforming, so if both clang and gcc agree, then I bet that MSVS is wrong... Or actually is not exactly wrong, just standard non-conforming. – Petr Nov 03 '15 at 14:36
  • Why is `p` type-dependent with `auto`? I can't find any evidence why would `auto` introduce [type dependency](http://en.cppreference.com/w/cpp/language/dependent_name#Type-dependent_expressions). Would you mind supporting this claim? – Avidan Borisov Nov 03 '15 at 15:02
  • Normally, I'd bet on MSVC to be wrong too, but in this case I'm not so sure. – Avidan Borisov Nov 03 '15 at 15:04
  • 4
    I wish Petr had edited the "speculation" phrase out of the answer when editing the clear explanation in. @Avidanborisov, what is still unclear? With `auto` the type of `p` depends on the type of `A::get()` which **you** know does not depend on the value of `cond` but the compiler is not permitted to know that. So with `auto` the type of `p` is unknown when parsing `p->is – JSF Nov 03 '15 at 15:10
  • @JSF, edited the speculation phrase out. – Petr Nov 03 '15 at 15:12
  • @JSF Thanks, that cleared it up. – Avidan Borisov Nov 03 '15 at 15:16