#c #templates #operator-overloading
Вопрос:
Я хотел бы распечатать экземпляр класса, он выглядит как не тип шаблона, но его указатель данных можно использовать для хранения нескольких данных(uchar/int/float), поэтому я придумал:
- перегрузите оператор потока, вызовите шаблонную версию
- напишите шаблонную версию оператора потока
Однако он просто не смог скомпилироваться:
#include lt;stdio.hgt; #include lt;iostreamgt; #include lt;memorygt; templatelt;typename Tgt; using Ptr = std::shared_ptrlt;Tgt;; using uchar = unsigned char; enum class ArrayType { UCHAR = 1, INT = 3, FLOAT = 4, }; class MagicArray { public: Ptrlt;uchar[]gt; data; ArrayType type; int bytes; public: MagicArray() : bytes(0), type(ArrayType::UCHAR), data(nullptr) {} MagicArray(int _bytes, ArrayType _type) : bytes(_bytes), type(_type), data(new uchar[_bytes]) { } public: int len() const { if (type == ArrayType::UCHAR) { return bytes; } else if (type == ArrayType::INT) { return bytes / sizeof(int); } else if (type == ArrayType::FLOAT) { return bytes / sizeof(float); } return -1; // not supported } }; templatelt;typename Tgt; std::ostreamamp; operator lt;lt; (std::ostreamamp; os, const MagicArrayamp; arr) { os lt;lt; "gt;gt;gt; the general one"; T* data = arr.data; for (int i = 0; i lt; arr.len(); i ) { os lt;lt; data[i] lt;lt; ", "; } os lt;lt; std::endl; } std::ostreamamp; operator lt;lt; (std::ostreamamp; os, const MagicArrayamp; arr) { switch(arr.type) { case ArrayType::UCHAR: return std::operatorlt;lt;lt;uchargt;(std::cout, arr); // !! this line, failed to compile case ArrayType::INT: return std::operatorlt;lt;lt;intgt;(std::cout, arr); // !! this line, failed to compile case ArrayType::FLOAT: return std::operatorlt;lt;lt;floatgt;(std::cout, arr); // !! this line, failed to compile } } int main() { MagicArray arr1(16, ArrayType::UCHAR); for (int i = 0; i lt; arr1.len(); i ) { arr1.data[i] = i; } MagicArray arr2(16, ArrayType::INT); for (int i = 0; i lt; arr2.len(); i ) { arr2.data[i] = i; } std::cout lt;lt; arr1 lt;lt; std::endl; std::cout lt;lt; arr2 lt;lt; std::endl; return 0; }
Примечание: класс MagicArray
, для этого вопроса, я бы не хотел менять его на тип шаблона.
Вопрос: Как я могу правильно распечатать экземпляр типа MagicArray в соответствии с их фактическим типом указателя данных, основываясь на приведенном выше коде?
=== обновление
То, что я думал, слишком просто. 1). Печать типов uchar приведет к появлению невидимых символов. 2). Я должен явно вызвать operatorlt;lt;
.
Теперь код решения будет выглядеть следующим образом:
templatelt;typename Tgt; std::ostreamamp; operator lt;lt; (std::ostreamamp; os, const MagicArrayamp; arr) { os lt;lt; "gt;gt;gt; operatorlt;Tgt; lt;lt; () "; T* data = (T*)arr.data.get(); for (int i = 0; i lt; arr.len(); i ) { os lt;lt; data[i] lt;lt; ", "; } os lt;lt; std::endl; return os; } templatelt;gt; std::ostreamamp; operator lt;lt; lt;uchargt; (std::ostreamamp; os, const MagicArrayamp; arr) { os lt;lt; "gt;gt;gt; operatorlt;uchargt; lt;lt; () "; uchar* data = (uchar*)arr.data.get(); for (int i = 0; i lt; arr.len(); i ) { os lt;lt; (int)(data[i]) lt;lt; ", "; } os lt;lt; std::endl; return os; } std::ostreamamp; operator lt;lt; (std::ostreamamp; os, const MagicArrayamp; arr) { switch(arr.type) { case ArrayType::UCHAR: return operatorlt;lt; lt;uchargt;(std::cout, arr); case ArrayType::INT: return operatorlt;lt; lt;intgt;(std::cout, arr); case ArrayType::FLOAT: return operatorlt;lt; lt;floatgt;(std::cout, arr); } } int main() { MagicArray arr1(16, ArrayType::UCHAR); uchar* ptr1 = (uchar*)arr1.data.get(); for (int i = 0; i lt; arr1.len(); i ) { ptr1[i] = i 100; } MagicArray arr2(16, ArrayType::INT); int* ptr2 = (int*)arr2.data.get(); for (int i = 0; i lt; arr2.len(); i ) { ptr2[i] = i; } std::cout lt;lt; arr1 lt;lt; std::endl; std::cout lt;lt; arr2 lt;lt; std::endl; return 0; }
Комментарии:
1. пожалуйста, укажите ошибку компилятора и желаемый результат
2. @463035818_is_not_a_number Хорошо… Я думаю, что нашел решение, обновленное в описании, поэтому я бы не вставлял ошибку..
3. если вы нашли решение, вы должны скорее опубликовать его в качестве ответа. После вашей правки вопрос становится еще менее ясным.
4. другими словами, в чем сейчас вопрос?
5. Первоначальная ошибка заключалась в наличии
std::
префикса пространства имен вoperatorlt;lt;
вызовах. Но затем, когда это было решено, возникла также проблема при попытке неявного преобразования ashared_ptr
в aT*
.