Re: Нестандартная перегрузка оператора вывода << :-D
От: Кодт Россия  
Дата: 31.10.09 00:56
Оценка: 3 (1)
1) Почему бы сразу не писать исходники в OEM-кодировке? Тогда пропадёт необходимость перекодировать на лету.
2) Расточительно написан код (копипаст работы с цветом). Я бы переделал...
class color_out
{
  ostream& ost_;
  unsigned color_;
  color_out(ostream& ost, unsigned c) : ost_(ost), color_(c) {}

  template<class T>
  const color_out& operator << (const T& rhs) const // спокойно можем работать с константами :)
  {
    output_colored(rhs);
    return *this;
  }
  const color_out& operator << (ostream&(manip*)(ostream&)) const // уточняем, с какой сигнатурой манипуляторов имеем дело
  {
    output_colored(manip);
    return *this;
  }

  // единый способ обрамить цветом
  template<class T>
  void output_colored(const T& rhs) const
  {
    unsigned const c = GetColor(); SetColor(color_); // преврати в SetConsoleColor сам
    output(rhs);
    SetColor(c);
    return *this;
  }

  // обрабатываем строки и всё остальное
  template<class T>
  void output(const T& v) const
  {
    ost_ << v;
  }
  void output(const string& v) const
  {
    output_oem(v.c_str());
  }
  void output(const char* v) const
  {
    output_oem(v);
  }
  void output(char c) const
  {
    const char s[2] = { c, 0 };
    output_oem(s);
  }

  // все строки - конвертируем одним и тем же способом
  void output_oem(const char* s) const
  {
    vector<char> buf(strlen(s)+1); // мультистринг не поддерживаем, ибо нафиг
    CharToOem(s, &buf.front());
    ost_ << &buf.front();
  }
};

template<ostream& Ost, unsigned Color>
struct the_color_out : color_out
{
  the_color_out() : color_out(Ost, Color) {}
};

typedef the_color_out<cerr, RED_ON_BLUE> critical;
typedef the_color_out<cout, RED_ON_BLACK> error;
typedef the_color_out<cout, YELLOW_ON_BLACK> warning;
typedef the_color_out<cout, GREEN_ON_BLACK> success;
// можно и глобальными, и статическими константами сделать - на вкус и цвет.

.....
critical() << "aaaaa!!!" << endl;


А что касается — почему у тебя ошибка компиляции была, так это просто.
Манипуляторы, такие как endl, имеют несколько сигнатур: ostream&(ostream&) и wostream&(wostream&).
Когда ты вызываешь функцию f(endl), компилятор пытается определить, какая из сигнатур тебе нужна.
А ты предлагаешь выбор из string, const char* и шаблонного T. Первые два не подходят, последний сохраняет неопределённость.

Кстати, если у тебя есть типы, которые умеют выводить себя в ostream, и при этом собираются вывести русские строки (ну например, ты определил ostream& operator<<(ostream&, const vector<string>&) и т.п.), то конвертирование на уровне обёртки над потоком уже не спасёт. Потому что внутри этого оператора про обёртку уже ничего не известно.
Следовательно, нужно вламываться внутрь ostream'а; это можно сделать двумя способами:
— унаследоваться от ostream и переопределить его виртуальные функции
написать собственный streambuf и назначить его ostream'у (т.е. прямо cout'у)
Последнее — идеологически наиболее правильно, хотя и трудоёмко.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.