Как передать контекстную информацию пользовательскому оператору << для std :: iostream

0

У меня есть сильно используемый (и оптимизированный) тип, который хранит ссылки на большее количество данных с помощью небольших целых чисел. Для отладки я хотел бы написать operator<< который запрашивает дополнительные данные для создания лучшего отладочного вывода. Как передать эту дополнительную контекстную информацию operator<<?

Вот пример:

/** Rich information */
struct Item {
  short id;
  std::string name;
  ...
};    
struct Database {
  std::map<short,Item> items;
  ...
};

/** Very optimized light-weight data type */
struct Foo {
  short a, b; // actually references to Item
};

/** for debugging etc. */
void print(std::ostream& os, const Foo& f, const Database& db) {
  os << "(" << db.items[f.a].name << "," << db.items[f.b].name << ")";
}

Database db;
items[0] = {0, "item0"};
items[1] = {1, "item1"};
Foo foo{0,1};

std::cout << "foo="; print(std::cout, foo, db); std::cout << std::endl; // ugly
std::cout << "foo=" << foo << std::endl; // How to get db ???
  • 0
    Разве Item в std::map<short, Item> является ItemData ?
  • 0
    Посмотрите соответствующую Item по short из Database ? Я действительно не понимаю, почему речь идет о потоках.
Показать ещё 2 комментария
Теги:
iostream

2 ответа

2
Лучший ответ

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

class print_database
{
public:
    print_database(const Foo& foo, const Database& db)
        : foo(foo), db(db)
    { }

    template<class cT>
    friend std::basic_ostream<cT>& operator<<(std::basic_ostream<cT>& os,
                                              const print_database& manip)
    {
        manip.print(os);
        return os;
    }
private:
    Foo foo;
    Database db;

    template<class cT>
    void print(std::basic_ostream<cT>& os) const
    {
        os << "(" << db.items[foo.a].name << "," << db.items[foo.b].name << ")";
    }
};

Тогда ваша функция print может быть реализована как:

print_database print(const Foo& foo, const Database& db)
{
    return print_database(foo, db);
}

Итак, теперь вы можете назвать это как:

std::cout << print(foo, db) << std::endl;
  • 0
    Есть ли причина, по которой вы используете std::basic_ostream<cT> вместо std::ostream ?
  • 0
    @Danvil Мы используем шаблонную версию, потому что пользователь может печатать с другим типом потока. Если вы собираетесь использовать только узкий символьный поток, тогда вы можете просто использовать std::ostream .
Показать ещё 2 комментария
1

Я не знаю, считаете ли вы его более или менее уродливым, но, возможно, что-то вроде:

debug_printer dp { db };
std::cout << dp(foo) << std::endl;

Где op<< - перегрузка для отладочного принтера; или op() может возвращать std::string.

  • 0
    И что бы сделал dp(foo) ?
  • 0
    @Danvil либо возвращает std::string , либо возвращает прокси-сервер, который фактически выполняет печать (имеется в виду, что это будет фактически какой-то генератор), либо устанавливает какое-то внутреннее состояние в принтере на «печать с едой».

Ещё вопросы

Сообщество Overcoder
Наверх
Меню