75

I don't get it, it seems to me that the call to f is completely unambiguous, but it fails to compile with expected primary-expression before ‘int’. If I comment out the line with the call to f, it compiles fine.

template<typename T>
struct A {
    template<typename S>
    void f() { }
};

template<typename T>
struct B : A<T> {
    void g() {
        this->f<int>();
    }
};
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Casey Rodarmor
  • 14,878
  • 5
  • 30
  • 33
  • 31
    I applaud you for not only finding this unholy problem but for never swearing once while describing it. –  Feb 09 '11 at 10:15

1 Answers1

139

This is due to a really obscure provision of the standard in which if you have a template that tries to access a template function in an object whose type depends on a template argument, you have to use the template keyword in a weird way:

this->template f<int>();

This is similar to the weirdness with typename that comes up with dependent types, except as applied to functions. In particular, if you leave out the template keyword, there's a parsing ambiguity between

this->f<int>()

(what you intended), and

((this->f) < int) > ()

which makes no sense (hence your error). The use of the keyword template here disambiguates and forces the compiler to recognize that it's looking at a perfectly valid call to a templated member function rather than a garbled mass of symbols.

starball
  • 20,030
  • 7
  • 43
  • 238
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 3
    I already knew a few syntax weirdnesses with templates, but I had never heard this one before. – Gorpik Feb 09 '11 at 08:50
  • @Gorpik: which is why you should avoid such things :) – akira Feb 09 '11 at 09:15
  • 1
    @templatetypedef: do you know if any compiler diagnoses this correctly ? It would be interested to see if CLang (which claim a friendly diagnosis) would suggest the insertion of `template` as a Fix hint, unfortunately I don't have it handy. – Matthieu M. Feb 09 '11 at 09:28
  • 73
    Not only the answer is good, but it has the added bonus that it has been provided by a user named templatetypedef :-) He surely knows what he's talking about... – Francesco Feb 09 '11 at 09:34
  • @Matthieu M.- This comes up so rarely that I've only seen it once and that was in g++, which had pretty uninstructive error messages. If there is a compiler with a good diagnostic for this, I haven't seen it. – templatetypedef Feb 09 '11 at 10:10
  • +1: I knew my bad knowledge of templates but that ! waw ! Good answer by "templatetypedef" with 42 badges ! A sign ;) – neuro Feb 09 '11 at 10:12
  • +1000 templatetypedef. And have mercy on your soul for even recognizing this problem and knowing what to do –  Feb 09 '11 at 10:15
  • Interestingly, Visual C++ 2010 doesn't treat this as an error, and compiles fine without the `template` keyword. Perhaps this has been improved in C++0x? – Pedro d'Aquino Feb 09 '11 at 10:43
  • 3
    Visual Studio is a bit lax on some template features. For example, it lets you omit typename in a few contexts where is technically required, and automatically imports names from template bases where it's not supposed to. I'd be surprised if this was in C++0x and not just a quirk in VS. – templatetypedef Feb 09 '11 at 10:44
  • 2
    @Pedro: it hasn't, Visual C++ is non compliant because it only checks the template at instantiation instead of two-phases look-up. – Matthieu M. Feb 09 '11 at 10:46
  • Wow, nutty! Thanks for the thorough answer :) – Casey Rodarmor Feb 11 '11 at 07:50
  • 1
    @Matthieu M.: So if non-compliance works better (in this case), what is gained? Asking out of genuine curiosity. – James Feb 15 '11 at 21:20
  • 3
    @James: you lose early diagnosis of obvious errors (lack of `;`, name typo, etc...) and you get a mess in overload resolution (normally, only functions declared prior to the template should be considered, but with this VC++ you can have functions declared afterward taken into account which the writer of the template may not have anticipated)... I would say it definitely does not work better. However it's pretty stupid for a compiler to issue such a stupid warning (it makes no sense to compare with a type...), but then gcc has never been reknown for its user friendliness :/ – Matthieu M. Feb 16 '11 at 07:11
  • Interestingly this happens for `A::f()` too, and the work around in that case is similar: `A::template f()`. – Michael Anderson Dec 30 '11 at 02:16
  • I liked C++, but the more I know this language, the more I find it badly designed... – Boiethios May 25 '16 at 08:08