Почему не шаблонный класс, используемый в качестве вложенного члена, является неполным типом?

#c #class #templates

#c #класс #шаблоны

Вопрос:

 #include<iostream> 
using namespace std; 

template <class T>
class Enclosing {       
    private:    
       int x; 
    public:

    class Nested { 
        Enclosing A  ;
        public:  
        void NestedFun() { 
            cout<<this->A.x;   
        }        
    }; 
};


int main() 
{  
    Enclosing<int>::Nested temp;
    return 0;
} 
  

Я пытаюсь объявить внутренний класс, вложенный с включающим типом. Код по-прежнему работает хорошо, пока я не устраню шаблон, появляются некоторые ошибки, а именно

 field 'A' has incomplete type 'Enclosing'
  

и

 forward declaration of 'class Enclosing'
  

Почему происходит это явление???

Ответ №1:

Когда Enclosing является шаблоном, определение типа A in Nested не требуется до Enclosing тех пор, пока не будет создан экземпляр, например, когда вы делаете:

 Enclosing<int>::Nested temp;
  

На данный момент, поскольку создание экземпляра происходит вне определения Enclosing , определение Enclosing уже завершено, и поэтому оно компилируется просто отлично.


С другой стороны, if Enclosing не является шаблоном, то, как только переменная A -член анализируется (при анализе определения Enclosing ), компилятор жалуется, что вы пытаетесь использовать определение неполного типа (что верно, поскольку вы все еще находитесь внутри определения A ).

Вы можете исправить это, только объявив Nested внутри Enclosing , а затем определив его вне Enclosing :

 class Enclosing 
{
   class Nested;  // just declaration
   // ...
};  // Enclosing is defined now

class Enclosing::Nested 
{ 
    Enclosing A;  // now ok, because Enclosing definition is complete
    // ...
}; 
  

Вот демонстрация.

Комментарии:

1. как насчет устранения шаблона и объявления Enclosing *A вместо Enclosing A во вложенном классе. Код все еще работает, несмотря на незавершенную конструкцию Enclosure

2. Да, это работает, потому что типы указателей могут быть объявлены без необходимости полного определения типов, на которые они указывают. So T t{}; не работает, но T *t{}; работает, когда T является неполным.