Зачем нам здесь typename?

template<class T>
class Set 
{
public:
   void insert(const T& item);
   void remove(const T& item);
private:
   std::list<T> rep;
}

template<typename T>
void Set<T>::remove(const T& item)
{
   typename std::list<T>::iterator it =  // question here
    std::find(rep.begin(),rep.end(),itme);
   if(it!=rep.end()) rep.erase(it);

}   

Почему требуется имя типа в remove()?

Ответы

Ответ 1

В общем, С++ нуждается в typename из-за неудачного синтаксиса [*], который он наследует от C, что делает невозможным без нелокальной информации говорить - например, - в A * B; - имена A тип (в этом случае это объявление B в качестве указателя на него) или нет (в этом случае это выражение умножения - вполне возможно, так как A, для всего, что вы можете сказать без нелокальной информации, может быть экземпляром класса, который перегружает operator*, чтобы сделать что-то странное; -).

В большинстве случаев у компилятора есть нелокальная информация, необходимая для устранения неоднозначности (хотя неудачный синтаксис по-прежнему означает, что низкоуровневому парсеру нужна обратная связь с уровня более высокого уровня, который хранит информацию в таблице символов)... но с шаблонов это не так (не в общем, хотя в этом конкретном случае было бы технически незаконным специализировать std::list<T>, чтобы его ::iterator не являлся типом имени; -).

[*] не только мое мнение, но и мнение Кен Томпсона и Роба Пайкса, в настоящее время моих коллег, которые заняты разработкой и внедрением нового языка программирования для внутреннего использования: этот новый язык программирования, в то время как его синтаксис в основном C-like, НЕ повторяет ошибки дизайна синтаксиса C - это новый язык (например, в хорошем старом Pascal), синтаксиса достаточно, чтобы отличать идентификаторы, которые должны называть тип из тех, которые не должны; -).

Ответ 2

Если вы говорите typename, который используется с std::list<T>::iterator:

Имя_файла используется, чтобы уточнить, что iterator - это тип, определенный в классе std::list<T>. Без typename std::list<T>::iterator будет считаться статическим членом. typename используется, когда имя, которое зависит от параметра шаблона, является типом.

Ответ 3

typename необходимо в вашем объявлении 'it', потому что иначе компилятор не знает, что это объявление типа, а не выражение.

В соответствии с эта страница, "Используйте ключевое слово typename, если у вас есть квалифицированное имя, которое ссылается на тип и зависит от параметра шаблона."

Ответ 4

Я думаю, в общем, вам нужно как typename/class T в объявлении класса, так и определения функций, потому что вы можете определить полные/неполные спецификации шаблона для определений функций. То есть. вы могли бы специализировать функцию удаления для ints, строк, независимо от того, что это произойдет. Поэтому в этом случае вы сообщаете компилятору "Это общий шаблон для любого типа", а затем вы можете определить ту же функцию, что и для целых чисел.