Я вывожу объекты своего класса, используя cout или ofstream. Я понял, что оператор вставки << — это стандартный способ преобразования объекта в строку или его печати. Я хотел бы использовать разные форматы в разных частях проекта.
Я хотел бы иметь для класса много разных форматов строк. Однако для класса может быть только один оператор вставки.
Каковы распространенные способы решения этой проблемы в C++?
Одно из решений, которое я использовал, — это иметь несколько функций, возвращающих строки. Насколько я понимаю, перегрузка оператора вставки является наиболее распространенным способом вывода объектов, и мне бы хотелось иметь такое решение.
Использование разных форматов звучит как образец стратегии. Я думаю, что шаблон также является мощным инструментом для решения многих проблем. Я не знаком ни с одним из вариантов решения.
Вот пример кода, демонстрирующий проблему:
#include <iostream>
#include <sstream>
class Point {
public:
Point(int x, int y): x(x), y(y) {}
std::string to_string() {
std::ostringstream stream;
stream << "(" << x << ", " << y << ")";
return stream.str();
}
friend std::ostream& operator<<(std::ostream& out, const Point& p) {
return out << p.x << " " << p.y;
}
private:
int x, y;
};
int main() {
Point p { 4, 2 };
std::cout << p << std::endl;
std::cout << p.to_string() << std::endl;
}
Я хотел бы избавиться от функции to_string и использовать операторы вставки для получения всех форматов. Каков простой способ определить, какой оператор вставки формата используется. Должна быть возможность изменить формат объекта.
Класс может иметь более двух разных форматов.
Если вы можете использовать C++20, есть std::format, который позволяет вам иметь printf выходные строки, но с безопасностью типов. std::formatter можно специализировать для вашего типа, чтобы он работал с ним std::format
Это позволит вам использовать значение по умолчанию, а затем вы сможете вручную указать любое специальное форматирование, которое вы хотите, на месте вызова.
Вы можете создать свой собственный манипулятор потока ввода-вывода и иметь поведение операторов потока своих собственных классов в зависимости от состояния манипулятора вашего клиента, которое вы ввели в поток. qv. пользовательские манипуляторы потоков C++. Однажды я пошел по этому пути и пришел к выводу, что это не решение моей проблемы (ввод-вывод одним из четырех способов: двоичный для файла, текстовый для файла, текстовый для пользователя, текстовый для -отладка). Но, возможно, это решение, подходящее для вашей проблемы.





Для этой задачи вы можете определить свои собственные манипуляторы потоков ввода-вывода. Вы также можете:
Point другим типом структуры/класса, для которого вы перегружаете operator<<, например:#include <iostream>
class Point {
public:
Point(int x, int y): x(x), y(y) {}
private:
int x, y;
friend struct s_Point_printer;
};
struct s_Point_printer {
const Point &m_pt;
const bool m_parenthesis;
s_Point_printer(const Point &pt, bool parenthesis) : m_pt(pt), m_parenthesis(parenthesis) {}
void printTo(std::ostream &out) const {
if (m_parenthesis)
out << "(" << m_pt.x << ", " << m_pt.y << ")";
else
out << m_pt.x << " " << m_pt.y;
}
friend std::ostream& operator<<(std::ostream &out, const s_Point_printer &printer) {
printer.printTo(out);
return out;
}
};
s_Point_printer with_parens( const Point& pt ) {
return s_Point_printer{pt, true};
}
s_Point_printer without_parens( const Point& pt ) {
return s_Point_printer{pt, false};
}
int main() {
Point p { 4, 2 };
std::cout << without_parens(p) << std::endl; // prints "4 2"
std::cout << with_parens(p) << std::endl; // prints "(4, 2)"
}
std::ostream, а затем перегрузить operator<< для Point, проверив этот параметр, например:class Point {
public:
static int point_xalloc;
Point(int x, int y): x(x), y(y) {}
friend std::ostream& operator<<(std::ostream& os, const Point& pt) {
if (os.iword(Point::point_xalloc) == 1)
return os << "(" << pt.x << ", " << pt.y << ")";
else
return os << pt.x << " " << pt.y;
}
private:
int x, y;
};
int Point::point_xalloc = std::ios_base::xalloc();
std::ios_base& with_parens(std::ios_base& os) {
os.iword(Point::point_xalloc) = 1;
return os;
}
std::ios_base& without_parens(std::ios_base& os) {
os.iword(Point::point_xalloc) = 0;
return os;
}
int main() {
Point p { 4, 2 };
std::cout << without_parens << p << std::endl; // prints "4 2"
std::cout << with_parens << p << std::endl; // prints "(4, 2)"
}
ваше решение в порядке. Конечно, есть разные способы, но если вы не хотите
to_string, чего еще вы хотите?std::cout << p;для одного формата, а что для другого?