Confusing Template error

后端 未结 4 1185
萌比男神i
萌比男神i 2020-12-04 11:44

I\'ve been playing with clang a while, and I stumbled upon \"test/SemaTemplate/dependent-template-recover.cpp\" (in the clang distribution) which is supposed to provide hint

相关标签:
4条回答
  • 2020-12-04 12:18

    Excerpt from C++ Templates

    The .template Construct A very similar problem was discovered after the introduction of typename. Consider the following example using the standard bitset type:

    template<int N> 
    void printBitset (std::bitset<N> const& bs) 
    { 
        std::cout << bs.template to_string<char,char_traits<char>, 
                                           allocator<char> >(); 
    } 
    

    The strange construct in this example is .template. Without that extra use of template, the compiler does not know that the less-than token (<) that follows is not really "less than" but the beginning of a template argument list. Note that this is a problem only if the construct before the period depends on a template parameter. In our example, the parameter bs depends on the template parameter N.

    In conclusion, the .template notation (and similar notations such as ->template) should be used only inside templates and only if they follow something that depends on a template parameter.

    0 讨论(0)
  • 2020-12-04 12:28

    Insert it just before the point where the caret is:

    template<typename T, typename U, int N> struct X {
         void f(T* t)
         {
            t->template f0<U>();
         }
    };
    

    Edit: the reason for this rule becomes clearer if you think like a compiler. Compilers generally only look ahead one or two tokens at once, and don't generally "look ahead" to the rest of the expression.[Edit: see comment] The reason for the keyword is the same as why you need the typename keyword to indicate dependent type names: it's telling the compiler "hey, the identifier you're about to see is the name of a template, rather than the name of a static data member followed by a less-than sign".

    0 讨论(0)
  • 2020-12-04 12:29

    In addition to the points others made, notice that sometimes the compiler couldn't make up his mind and both interpretations can yield alternative valid programs when instantiating

    #include <iostream>
    
    template<typename T>
    struct A {
      typedef int R();
    
      template<typename U>
      static U *f(int) { 
        return 0; 
      }
    
      static int f() { 
        return 0;
      }
    };
    
    template<typename T>
    bool g() {
      A<T> a;
      return !(typename A<T>::R*)a.f<int()>(0);
    }
    
    
    int main() {
      std::cout << g<void>() << std::endl;
    }
    

    This prints 0 when omitting template before f<int()> but 1 when inserting it. I leave it as an exercise to figure out what the code does.

    0 讨论(0)
  • 2020-12-04 12:38

    ISO C++03 14.2/4:

    When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

    In t->f0<U>(); f0<U> is a member template specialization which appears after -> and which explicitly depends on template parameter U, so the member template specialization must be prefixed by template keyword.

    So change t->f0<U>() to t->template f0<U>().

    0 讨论(0)
提交回复
热议问题