Как перегрузить операторы >> и << для разного типа файлов

У меня есть структура на подобии такой :

struct Product 
{
    int code;
    char name[10];
    int price;
};

Я хочу, чтобы она могла записываться в файлы как бинарного формата, так и файлы обычного формата.

Перегрузил операции для бинарного формата :

std::ofstream& operator<<(std::ofstream& out, const Product& product) {
    out.write((char*)&product.code, sizeof(product.code));
    out.write((char*)&product.name, sizeof(product.name));
    out.write((char*)&product.price, sizeof(product.price));
    return out;
}

std::ifstream& operator>>(std::ifstream& in, Product& product) { 
    in.read((char*)&product.code, sizeof(product.code));
    in.read((char*)&product.name, sizeof(product.name));
    in.read((char*)&product.price, sizeof(product.price));
    return in;
}

Однако как их перезагрузить и для обычного формата? Ибо синтаксис в бинарном файле и синтаксис в обычном файле различаются, из-за чего у меня на выходе выходит непойми что.


Ответы (1 шт):

Автор решения: Alex Guteniev

Хороший вопрос, на который, как мне кажется, нет хорошего ответа в рамках потоков С++

Есть следующие механизмы, которые вроде как призваны управлять форматом вывода, но они не помогут:

  • i/o манипуляторы вроде std::boolalpha. Меняют состояние потока, устанавливая соотвествующий std::ios_base::fmtflags. Свой флаг добавить к стандартным нельзя
  • режим открытия файла binary. тут проблема с эффективностью и валидностью приведения произвольного ostream к ofstream (в общем случае оператор << следует писать для ostream вообще, а не для ofstream), плюс binary режим не для этого, и подобное нарушает принцип наименьшего удивления

Как воркэраунд, выглядящий не очень большим злом, я бы предложил сделать отдельные типы со ссылочной сематникой, сериализующие Product. Например шаблонные SerializeAsText<T> и SerializeAsBinary<T> со специализациями SerializeAsText<Product> SerializeAsBinary<Product>. Ну или не шаблонные.

Как совсем костыли, скрытое состояние потока в мапе, в глобальной переменной или thread local storage переменной.

В библиотеках сериализации, вроде boost serialization, бинарность сериализации данных является свойством потока, клиентский код просто делает out << product.code (или даже s & product.code при совмещенной реализации сериализации и десериализации)

→ Ссылка