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'у)
Последнее — идеологически наиболее правильно, хотя и трудоёмко.