Я пытаюсь перегрузить оператор потока в качестве диагностического инструмента для различных объектов в моем коде. В идеале я хотел бы иметь возможность изменять поток на лету с этими флагами-модификаторами потока, однако они очень ограничены, и я не хочу разбрасывать флаги setVerbose в каждый из моих объектов. Я получил следующее довольно плохое, но работающее решение
#include <iostream>
#include <string>
#include <vector>
struct StructA {
std::string mLongName;
std::string mShortName;
inline friend std::ostream& operator << (std::ostream& os, const StructA& rStruct) {
// I dont know how to use a generic verbose flag - so use this - very bad idea
// but perhaps the stackoverflow people can help out with a good suggestion
if (os.flags() & os.skipws) {
os << rStruct.mShortName << std::endl;
} else {
os << rStruct.mLongName << std::endl;
}
return os;
}
};
int main()
{
StructA test {"Verbose Name", "Short Name"};
std::cout << test << std::noskipws << test << test << std::skipws << test;
}
Я создал выше живой пример чтобы продемонстрировать мою точку зрения, и он выводит следующий вывод:
Short Name
Verbose Name
Verbose Name
Short Name
Как вы можете видеть, я использую совершенно неподходящий флаг модификатора потока ‘skipws’ в качестве подробного флага 1-го уровня бедного человека — это было просто для того, чтобы показать подход в потоке, который я искал, без havnig для добавления объекта-члена к каждому из моих печатные объекты (приветствуются все предложения по лучшим подходам, но я бы хотел свести к минимуму изменения для каждого из моих печатных объектов — у меня их довольно много). Во-вторых, флаг сохраняется до тех пор, пока не будет сброшен позже — некоторые другие флаги потока действуют только для оператора следующего потока, но я не совсем уверен, как это работает, и в-третьих
Вы можете сохранить пользовательское состояние в своем экземпляре потока:
Видеть это Жить на Колиру
#include <iostream>
static int const index = std::ios_base::xalloc();
std::ostream& verbose(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}
std::ostream& noverbose(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}
struct StructA {
std::string mLongName;
std::string mShortName;
inline friend std::ostream& operator << (std::ostream& os, const StructA& rStruct) {
switch (os.iword(index)) {
case 1: return os << rStruct.mLongName;
case 0:
default: return os << rStruct.mShortName;
}
}
};
int main()
{
StructA a;
a.mLongName = "loooooooooooooooooooong names are tedious";
a.mShortName = "succinctness";
std::cout << a << '\n';
std::cout << verbose;
std::cout << a << '\n';
std::cout << noverbose;
std::cout << a << '\n';
}
Кредиты идут в Дитмар Кюль ответ.
Если вам нужно значительное количество состояния / логики, вам придется взглянуть на наполнение пользовательского аспекта локали. Его ответ также показывает основы этого подхода.
Кажется, в этом случае вы слишком неохотно по какой-то причине создаете абстракцию. Не принимайте это на свой счет, я пишу это только потому, что когда-то слишком колебался, но создавал абстракции. Создайте класс Logger на основе iostream либо путем наследования, либо с учетом содержания, поведение которого вы можете изменить. Допустим, у логгера есть такие параметры, как
enum {SHORT,VERBOSE,DEBUG};
Пусть этот параметр будет статическим, чтобы он оказывал влияние на все приложения во всех случаях. Неужели нужен только один экземпляр?
Я понимаю, что все ваши печатаемые объекты должны согласованно поддерживать различные параметры печати, то есть все они должны иметь shortName и longName.