Запутанная ошибка шаблона
я играл с 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 ответа:
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 (
в заключение .нотация шаблона (и подобные нотации, такие как ->шаблон) должны использоваться только внутри шаблонов и только если они следуют чему-то, что зависит от параметра шаблона.