использование флагов ostream в качестве подробного флага отладки

Я пытаюсь перегрузить оператор потока в качестве диагностического инструмента для различных объектов в моем коде. В идеале я хотел бы иметь возможность изменять поток на лету с этими флагами-модификаторами потока, однако они очень ограничены, и я не хочу разбрасывать флаги 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 для добавления объекта-члена к каждому из моих печатные объекты (приветствуются все предложения по лучшим подходам, но я бы хотел свести к минимуму изменения для каждого из моих печатных объектов — у меня их довольно много). Во-вторых, флаг сохраняется до тех пор, пока не будет сброшен позже — некоторые другие флаги потока действуют только для оператора следующего потока, но я не совсем уверен, как это работает, и в-третьих

2

Решение

Вы можете сохранить пользовательское состояние в своем экземпляре потока:

Видеть это Жить на Колиру

#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';
}

Кредиты идут в Дитмар Кюль ответ.

Если вам нужно значительное количество состояния / логики, вам придется взглянуть на наполнение пользовательского аспекта локали. Его ответ также показывает основы этого подхода.

2

Другие решения

Кажется, в этом случае вы слишком неохотно по какой-то причине создаете абстракцию. Не принимайте это на свой счет, я пишу это только потому, что когда-то слишком колебался, но создавал абстракции. Создайте класс Logger на основе iostream либо путем наследования, либо с учетом содержания, поведение которого вы можете изменить. Допустим, у логгера есть такие параметры, как

enum {SHORT,VERBOSE,DEBUG};

Пусть этот параметр будет статическим, чтобы он оказывал влияние на все приложения во всех случаях. Неужели нужен только один экземпляр?

Я понимаю, что все ваши печатаемые объекты должны согласованно поддерживать различные параметры печати, то есть все они должны иметь shortName и longName.

2

По вопросам рекламы [email protected]