вставка объектов в ostreams - PullRequest
0 голосов
/ 23 ноября 2011

Я хочу поместить текстовое описание экземпляра класса в ostream, как в

ostream << myInstance;

Я знаю, как объявить ostream-инсертор;

ostream& operator<<(ostream&, myClass&);

Я хочу иметь возможность добавлять разные уровни детализации в ostream. Я мог бы сделать это, если бы мог определить два или более ostream-вставки, или передать дополнительный аргумент для вставки, или передать метод для вставки, или, возможно, вызвать метод, который возвращает поток строк (я могу это сделать?)

Кто-нибудь решил эту проблему?

Ответы [ 4 ]

2 голосов
/ 23 ноября 2011

Стандартным решением является определение пользовательского манипулятора с использованием флагов или другой информации о форматировании, хранящейся в данных, предоставленных ios::xalloc.Что-то вроде:

int
flagIndex()
{
    static int const theIndex = std::ostream::xalloc();
    return theIndex;
}

std::ostream&
verbose( std::ostream& stream )
{
    stream.iword( flagIndex() ) = 1;
    return stream;
}

std::ostream&
unverbose( std::ostream& stream )
{
    stream.iword( flagIndex() ) = 0;
    return stream;
}

std::ostream&
operator<<( std::ostream& dest, MyClass const& object )
{
    bool verbose = dest.iword( flagIndex() ) != 0;
    //  ...
    return dest;
}

Вы можете написать что-то вроде:

std::cerr << verbose << myObject;
2 голосов
/ 23 ноября 2011

Вы можете добавить «флаги» в поток, фактически инкапсулируя сам поток.

struct Verbose {
  explicit Verbose(std::ostream* s = 0): _stream(s) {}
  std::ostream* _stream;
};

Verbose operator<<(std::ostream& out, Verbose) {
  return Verbose(&out);
}

И затем вы определяете новый оператор для подробного вывода:

std::ostream& operator<<(Verbose v, MyClass const& mc) {
  assert(v._stream);
  std::ostream& out = *v._stream;

  // ...
  return out;
}

Использование:

std::cout << Verbose() << myInstance << "\n";

Вы заметите, что Verbose вообще не привязан к классу и может быть легко повторно использован в разных классах.

Примечание: если вы хотите,Вы можете добавить дополнительный параметр к Verbose, чтобы фактически контролировать уровень многословия непосредственно там.

1 голос
/ 23 ноября 2011

Вы не можете добавить дополнительные параметры к operator<<, но вы можете легко определить пользовательскую функцию печати, принимая параметр подробность :

void dump(ostream& ostr, const myClass& obj, int verbosity = 1)
{
    if (verbosity > 2)
      ostr << "Very verbose!\n";
    if (verbosity > 1)
      ostr << "Verbose!\n";
    if (verbosity > 0)
      ostr << "Standard!\n";
    ostr << "Minimal.\n";
}

Использование:

dump(cout, myobj);     // Default
dump(cout, myobj, 0);  // Minimal
dump(cout, myobj, 1);  // Default
dump(cout, myobj, 2);  // Verbose
dump(cout, myobj, 3);  // Very verbose

Вы должны также обеспечить переадресацию оператора потока на dump(), используя многословность по умолчанию:

ostream& operator<<(ostream& ostr, const myClass& obj)
{
    dump(ostr, obj);
    return ostr;
}

Если вы хотите пойти по этому пути, было бы неплохо объявить enum для многословия вместо использования int s:

enum Verbosity
{
    MinimalOutput = 0,
    StandardOutput = 1,
    VerboseOutput = 2,
    DebugOutput = 3
};
0 голосов
/ 23 ноября 2011

Стандартный способ изменить форматирование вашего элемента - реализовать манипулятор. Обычно это будет немного больше, чем установка некоторых флагов. Ваш инсертер затем изменит свое поведение в зависимости от состояния флага (ов).

...