Я создал следующую программу
#include <iostream>
#include <typeinfo>
template<class T>
struct Class
{
template<class U>
void display(){
std::cout<<typeid(U).name()<<std::endl;
return ;
}
};
template<class T,class U>
void func(Class<T>k)
{
k.display<U>();
}
int main()
{
Class<int> d;
func<int,double>(d);
}
Вышеуказанная программа не компилируется, поскольку display ()
является шаблоном функция-член, поэтому необходимо выполнить квалификацию .template
перед display ()
. Я прав?
Но когда я сделал следующую программу
#include <iostream>
#include <typeinfo>
template<typename T>
class myClass
{
T dummy;
/*******/
public:
template<typename U>
void func(myClass<U> obj);
};
template<typename T>
template<typename U>
void myClass<T>::func(myClass<U> obj)
{
std::cout<<typeid(obj).name()<<std::endl;
}
template<class T,class U>
void func2(myClass<T>k)
{
k.template func<U>(k); //even it does not compile
}
int main()
{
myClass<char> d;
func2<char,int>(d);
std::cin.get();
}
, почему k.func
не компилируется даже после предоставления конструкции .template
?
Символ <
означает как «меньше», так и «начало аргументов шаблона». Чтобы различать эти два значения, синтаксический анализатор должен знать, называет ли предыдущий идентификатор шаблон или нет.
Например, рассмотрим код
template< class T >
void f( T &x ) {
x->variable < T::constant < 3 >;
}
Либо T :: variable
, либо T :: constant
должны быть шаблоном. Функция означает разные вещи в зависимости от того, что есть, а что нет:
T :: constant
сравнивается с 3, и логический результат становится аргументом шаблона для T :: variable <>
T :: constant <3>
сравнивается с x-> переменной
. Чтобы устранить неоднозначность, ключевое слово шаблона
требуется перед переменной
или константой
. Случай 1:
template< class T >
void f( T &x ) {
x->template variable < T::constant < 3 >;
}
Случай 2:
template< class T >
void f( T &x ) {
x->variable < T::template constant < 3 >;
}
Было бы неплохо, если бы ключевое слово требовалось только в реальных неоднозначных ситуациях (что бывает редко), но это значительно упрощает написание синтаксического анализатора и предотвращает такие проблемы. застать вас врасплох.
Стандартные см. 14.2 / 4:
Когда имя шаблона элемента специализация появляется после. или -> в постфиксном выражении или после вложенный-указатель-имени в квалифицированный идентификатор, а постфиксное-выражение или квалифицированный-идентификатор явно зависит от параметр-шаблон (14.6.2), имя шаблона участника должно иметь префикс по шаблону ключевого слова. В противном случае имя предполагается, чтобы назвать не шаблон.
Раздел 5.1 Шаблонов C ++ подробно объясняет эту конструкцию
У функции ниже есть проблема
template<class T,class U>
void func2(myClass<T> k)
{
k.template func<U>(k); //even it does not compile
}
Здесь вызывается T = char и U = int
myclass<char>::func<int>(myclass<char>)
. Однако такой функции не существует
. Хотя в обычных обстоятельствах char можно преобразовать в int, это не работает для явно указанных аргументов шаблона
Стандарт требует ключевых слов template
или typename
для устранения неоднозначности вещей, которые зависят от контекста шаблона .
Первый пример компилируется и отлично работает в VS 2010.