Запутанная ошибка шаблона


я играл с clang некоторое время, и я наткнулся на "test/SemaTemplate/dependent-template-recover.cpp " (в дистрибутиве clang), который должен предоставлять подсказки для восстановления после ошибки шаблона.

все это можно легко урезать до минимального примера:

template<typename T, typename U, int N> struct X {
    void f(T* t)
    {
        // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
        t->f0<U>();
    }
};

сообщение об ошибке, полученное clang:

tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
         t->f0<U>();
            ^
            template 
1 error generated.

... Но мне трудно понять, где именно предполагается вставить template для сайта код должен быть синтаксически правильным?

4 71

4 ответа:

ISO C++03 14.2 / 4:

когда имя специализации шаблона члена появляется после . или -> в постфиксное выражение, или после вложенных-имя-описатель в квалифицированный-идентификатор, и постфиксное-выражение или квалифицированный-идентификатор явным образом зависит от шаблона параметра (14.6.2), имя шаблона элемента должно иметь префикс ключевого слова template. В противном случае предполагается, что имя не является шаблоном.

на t->f0<U>();f0<U> является членом шаблон специализации, которая появляется после -> и которая явно зависит от параметра шаблона U, поэтому специализация шаблона члена должна иметь префикс template ключевое слово.

так изменить t->f0<U>() до t->template f0<U>().

в дополнение к другим пунктам, обратите внимание, что иногда компилятор не мог решить, и обе интерпретации могут дать альтернативные действительные программы при создании экземпляра

#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;
}

это выводит 0 при пропуске template до f<int()> но 1 при его установке. Я оставляю это как упражнение, чтобы выяснить, что код делает.

вставьте его непосредственно перед точкой, где каретка:

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

Edit: причина этого правила становится яснее, если вы думаете, как компилятор. компиляторы обычно смотрят только вперед один или два токена сразу, и обычно не "смотрят вперед" на остальную часть выражения.[Edit: см. комментарий] причина ключевого слова такая же, как и то, почему вам нужен typename ключевое слово для указания имен зависимых типов: оно говорит компилятору " Эй, идентификатор, о котором вы говорите чтобы увидеть-это имя шаблона, а не имя статического элемента данных, за которым следует знак меньше, чем".

фрагмент Шаблоны C++

The .шаблонная конструкция Очень похожая проблема была обнаружена после введения typename. Рассмотрим следующий пример использования стандартного типа битов:

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

странная конструкция в этом примере .шаблон. Без этого дополнительного использования шаблона компилятор не знает, что следующий токен less-than (

в заключение .нотация шаблона (и подобные нотации, такие как ->шаблон) должны использоваться только внутри шаблонов и только если они следуют чему-то, что зависит от параметра шаблона.