2

The following code compiles under Visual Studio 2013, and fails to compile under gcc/clang (all tested versions).

clang: error: use 'template' keyword to treat 'write' as a dependent template name

gcc: error: expected primary-expression before ‘int’

Both errors occur where indicated in the code

template <typename Itr>    
struct A {        
    template <typename Other>    
    void write(Other x) {}    
};      

template <class T>    
struct B {       
   A<T>& a;    
   B(A<T>& a) : a(a) {    
      // error: use 'template' keyword to treat 'write' as a dependent template name    
      a.write<int>(5);    
   }    
}; 

int main() {    
    A<int> a;    
    // Fine    
    a.write<int>(5);    
    B<int> b(a);    
}

Experience tells me that Visual Studio is probably wrong, but I'm not sure why this should fail to compile when A<T> is fully specified, and I'm only wanting to call a template method whose type I specify.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • 1
    I see this is marked as a duplicate, and yeah, it technically is.. But surely you can understand how a person managed to make this mistake when you need to understand the standard's very technical wording to make that connection. Also from the examples in that question, it isn't immediately clear that this is related. I personally think this is a useful question, but whatever. – user3870920 Sep 04 '15 at 00:39
  • 3
    A question being marked a duplicate isn't a negative reflection on the question. This question is perfectly fine. It's just that it's been asked before, and the linked question has a very thorough explanation of the problem and the solution. Duplicates stay alive forever to be used as signposts. Closed questions are deleted. – Barry Sep 04 '15 at 00:44
  • @Barry Ah, right! Good to know, thanks – user3870920 Sep 04 '15 at 00:49

1 Answers1

2

From [temp.names], emphasis mine:

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.

Here, write is a member template specialization that appears after a . in a postfix-expression, and a is type-dependent (it depends on T), and a is not a member of the current instantiation (which would be B<T>), so it must be prefixed with template. gcc and clang are correct to reject this code, as it should be treated as if write were a non-template and the < were an operator - which is invalid.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • 2
    Great, thanks. I really need to improve my standard searching skills. Is it just me or does the correct version, `a.template write(5)` look incredibly... weird? – user3870920 Sep 04 '15 at 00:35
  • @user3870920 It is what it is. – Barry Sep 04 '15 at 00:38
  • 1
    C++ gets more and more obscure the more they try to make template work. My approach: Use templates conservatively and stick to "c with classes" - c++ :) – BitTickler Sep 04 '15 at 00:40