1

Я пытаюсь узнать о шаблонах и специализации шаблонов. Я пишу класс шаблона для массивов, используя специализацию шаблонов, чтобы избежать раздувания кода. Таким образом, у меня есть полностью специализированный шаблон MyArray, а затем я наследую его от class MyArray<T*> : private MyArray<void*>. У меня возникли проблемы с перегрузкой индексированных операторов (один для non-const refs, один для const refs). Вот фрагмент кода (далеко не полный, но содержит мою проблему).Перегрузка оператора для частичной специализации шаблона

#include <iostream> 
using std::cout; 
using std::cin; 
using std::endl; 

/*** template class MyArray **/ 
template <class T> 
class MyArray {}; 

/*** Full template specialization for MyArray holding pointers ***/ 
template <> 
class MyArray<void*> { 
    public: 
     explicit MyArray(unsigned s = 100) : sz(s) { 
      data = new void*[s]; 
     } 
     virtual ~MyArray() { delete[] data; } 

     /** subscript operator overload for non-const refs **/ 
     void*& operator[](unsigned i) { 
      return data[i]; 
     } 

     /** subscript operator overload for const refs **/ 
     const void*& operator[](unsigned i) const { 
      return data[i]; // line 26 
     } 

     unsigned size() const { return sz; } 

    private: 
     void** data; 
     unsigned sz; 
}; 

/** Partial specialization: create the template class by inheriting from the one above **/ 
template <class T> 
class MyArray<T*> : private MyArray<void*> { 
    public: 
     explicit MyArray(unsigned s = 100) : MyArray<void*>::MyArray(s) { 
      data = new T*[s]; 
     } 
     virtual ~MyArray() { delete[] data; } 

     /** subscript operator overload for non-const refs **/ 
     T*& operator[](unsigned i) { 
      return reinterpret_cast<T*&>(  // line 47 
       MyArray<void*>::operator[](i) 
      ); 
     } 
     /** subscript operator overload for const refs **/ 
     const T*& operator[](unsigned i) const { 
      return reinterpret_cast<const T*&>(
       MyArray<void*>::operator[](i) 
      ); 
     } 


     unsigned size() const { return MyArray<void*>::size(); } 

    private: 
     T** data; 

}; 

/** input function for filling MyArray's **/ 
template <class T> 
void InputMyArray(MyArray<T*>& my_array) { 
    unsigned size = 0; 
    T tmp; 
    while (cin >> tmp) { 
     T* i = new T; 
     *i = tmp; 
     my_array[size++] = i; 
    } 
} 

/** output function for printing elements of MyArray's **/ 
template <class T> 
void OutputArray(const MyArray<T*>& my_array) { 

    for (unsigned i = 0; i < my_array.size(); i++) { 
     cout << *my_array[i] << " "; 
    } 
    cout << endl; 
} 

int main() { 
    /** Initialize array, fill it, print contents **/ 
    MyArray<int*> p; 
    InputMyArray(p); 
    cout << "MyArray of pointer to ints holds int values: " << endl; 
    OutputArray(p); 

    return 0; 
} 

Компилятора (лязг) жалуется (ошибка) около линии 26

Неконстантной именующей ссылка на тип «константный пустот *» не может связываться с величиной несвязанного типа «недействительными *»

Я полагаю, что я не хочу, чтобы компилятор интерпретировал это как неконстантную ссылку - я хочу, чтобы он был const. Как я могу правильно перегрузить этот оператор в этом контексте? Соответствующий фрагмент кода отлично работает для класса шаблона без специализации, например MyArray<T>.

Компилятор далее жалуется (предупреждения) о reinterpret_cast с, по-видимому содержат неопределенное поведение

reinterpret_cast от 'пустоты *' до 'междунар * &' имеет неопределенное поведение

(линия 47). reinterpret_casts по существу скопированы с моих инструкций, поэтому я думаю, что они будут использоваться так. Не знаю, почему ссылка на void* не поднята. Что я здесь делаю неправильно?

+0

[OT]: Ваше наследство кажется странным, как вы не факторизовать кода, дублирующие пользователей (переменная и метод) ... и вы вводите литье, тогда как код может быть безопасным ... – Jarod42

+0

Даже если вам удастся скомпилировать это, каждый из ваших объектов будет иметь два элемента данных. Тот, который используется, также скрыт другим. – qPCR4vir

+0

Реорганизация вашего кода и использование нескольких способов использования сделают все проще. – qPCR4vir

ответ

0

Шаблон представляет собой контейнер для void*, не const void*:

/** subscript operator overload for const refs **/ 
    void* const& operator[](unsigned i) const { 
     return data[i]; // line 26 
    } 

То же самое для T*:

/** subscript operator overload for const refs **/ 
    T* const& operator[](unsigned i) const { 
     return reinterpret_cast<T*const&>(
      MyArray<void*>::operator[](i) 
     ); 
    } 
+0

Это действительно заставляет замолчать компилятор. Но тогда мне нужно следить - я не хочу T * const &, потому что тогда я могу изменить объект T *. Разве дело не в том, чтобы иметь две версии оператора нижнего индекса, что один из них не позволяет изменять объекты контейнера (т. Е. Только для чтения) - как я мог бы это достичь? – pengwing

+1

Вы можете вернуть 'const T *', чтобы отключить модификацию объекта 'T', с ответом на код, вы не можете изменить * указатель *. – Jarod42

+0

Уверен, что вы можете? Сама ссылка является константой и не может быть изменена, но ее можно использовать для изменения указателя, к которому она относится.EDIT: извините, я запутался здесь, смешав указатели и ссылки. Я все еще немного запутался в этом - если в контейнере будут храниться объекты, а не указатель, было бы нормально писать const T & operator ..., правильно? – pengwing

Смежные вопросы