Оператор потока перегрузки для типа шаблона

#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; вызовах. Но затем, когда это было решено, возникла также проблема при попытке неявного преобразования a shared_ptr в a T* .