Задачи области в шаблоне C ++ - PullRequest
1 голос
/ 30 сентября 2010

Есть ли какие-либо проблемы с областью в этой программе?

#include<iostream>

using namespace std;

template<class Type>
class Base
{
   public:
   Type member;
   Base(Type param): member(param){

   }
};

template<class Type>
class Derived: public Base<Type>
{
    public:               
    Derived(Type param):Base<Type>(param){
     //                       ^
     //                       |_______  Not writing Type here gives error, why?
    }
    void display()
    {
        cout << member; /** ERROR HERE **/
    }
};

int main()
{
   Derived<int> p(5);
   p.display();
   return 0;
}

Я получаю ошибку 'member' was not declared in this scope.Как исправить проблемы?

Ответы [ 5 ]

10 голосов
/ 30 сентября 2010

Ваш вопрос несколько сбивает с толку. Сначала я подумал, что вы спрашиваете о base<Type> в списке инициализации члена, затем я подумал, что вы спрашиваете о доступе к member, затем снова к первому ... Теперь я думаю, что вы спрашиваете обоим, поэтому я отвечу на оба.


Не пишет Type здесь выдает ошибку, почему?

Когда вы используете имя шаблона класса (my_class_templ), оно ссылается на шаблон , который не является типом. Чтобы использовать его как тип, вам необходимо предоставить параметры шаблона (my_class_templ<int>, my_class_templ<T>). Поэтому, где бы ни требовалось имя типа (включая имена базовых классов в списке инициализации), вы должны предоставить параметры шаблона.

Вы можете опустить список параметров шаблона для имен шаблонов классов в пределах определения шаблона класса. Например, конструктор копирования может быть объявлен как

 my_class_templ(const my_class_templ& rhs);

вместо

 my_class_templ<T>(const my_class_templ<T>& rhs);

Это просто немного синтаксического сахара, позволяющего печатать меньше.

Однако, вне определения шаблонов классов, вам нужно явно прописать все параметры шаблона. Это также верно для производных классов:

my_dervied_class_templ(const my_derived_class_templ& rhs)
 : my_class_templ<T>(rhs)                          // need to spell out <T> here
{
}

Я получаю ошибку 'member' was not declared in this scope. Как исправить проблемы?

Когда ваш шаблон встречается компилятором первым, есть только его определение, и компилятор еще не видел его экземпляров. Компилятор не знает, могут ли в момент создания быть специализации шаблона в области видимости или нет. Тем не менее, вы могли бы специализировать свой шаблон для Base<T>::member, чтобы ссылаться на что-то другое или не определять полностью. (Скажем, специализация Base<void> не имеет элемента данных.) Следовательно, компилятор не должен рассуждать о членах Base. Следовательно, они не будут найдены в Derived.

В результате этого, если вам нужно обратиться к одному из членов Base, вам нужно сообщить компилятору, что вы ожидаете, что Base<T> будет иметь такого члена. Это делается путем полной квалификации его имени: Base<Type>::member.

8 голосов
/ 30 сентября 2010

Не писать Тип здесь дает ошибку, почему?

Если вы опустите Type, компилятор не сможет решить, является ли Base базовым классом или нетчлен Derived.Указание Type гарантирует, что Base является классом шаблона [базовый класс].

'member' не был объявлен в этой области

Это что-то дляделать с правилами для поиска имени (зависимые базовые классы).

C ++ 03 [Раздел 14.6 / 8] говорит

При поиске объявления имени, используемого вопределение шаблона, обычные правила поиска (3.4.1, 3.4.2) используются для независимых имен.Поиск имен, зависящих от параметров шаблона, откладывается до тех пор, пока фактический аргумент шаблона не станет известен (14.6.2).

Now Section 14.6.2/3 говорит

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

member является неквалифицированным именем, поэтому базовый класс не проверяется.

Таким образом, у вас есть два варианта.

  1. Используйте полностью определенное имя Member т.е. Base<Type>::member
  2. Используйте this->member.
2 голосов
/ 30 сентября 2010

Стандарт C ++ требует, чтобы компилятор выполнял «двухфазный поиск» для шаблонов.То есть они пытаются разрешить все независимые имена (имена, которые не зависят от параметров шаблона) на первом этапе, когда анализируется шаблон, и все зависимые имена на втором этапе, когда создается экземпляр шаблона.

Если вы не квалифицируетесь member, оно обрабатывается как независимое имя и поиск завершается неудачей на первом этапе.Вы можете решить эту проблему, добавив this-> к нему.Это делает member зависимым именем, и поиск задерживается до тех пор, пока вы на самом деле не создадите экземпляр шаблона.

2 голосов
/ 30 сентября 2010

В тот момент, когда компилятор читает шаблон (а не когда он его создает), он не может сказать, что такое Base<Type> (он может быть специализированным), и, следовательно, не пытается определить, имеет ли он элемент member,Вы должны точно сказать это: cout << this->Base<Type>::member;.

Я думаю (проверьте это, я не уверен), что using Base<Type>::member в области видимости класса тоже работает.

0 голосов
/ 30 сентября 2010
Derived(Type param):Base<Type>(param){ 

Это Base<Type> требуется, потому что основание Derived равно Base<T>.Ничто не называется Base.

void display()   
{   
        //cout << member; /** ERROR HERE **/ 
        cout << this->member;
        cout << this>Base<Type>::member;  
}

В качестве альтернативы наличие объявления использования в области действия 'Derived' также является допустимым методом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...