1) hex не работает с параметром 10. <<
операторы связывают слева направо, что означает, что ваш код такой же, как:
(mystream<<hex)<<10;
Таким образом, ваша перегрузка должна возвращать объект, который при смещении 10 печатает в шестнадцатеричном формате (или, если не печатает, записывает данные куда-то). Как все говорят, это делается путем сохранения флагов в самом объекте потока, а затем возврата *this
. Причина использования флагов заключается именно в том, что «10» еще не доступен, так как второй <<
еще не был оценен. Первый оператор <<
не может ничего напечатать - ему просто нужно подготовиться к вызову второго.
2) hex - это функция. Это можно сравнить с другими функциями:
ostream &operator<<(ostream &s, ios_base& (*m)(ios_base &)) {
if (m == hex) {
} else if (m == oct) {
} else if (m == dec) {
}
}
За исключением случаев, когда вы обычно этого не хотите, вам нужно поведение по умолчанию, которое выглядит примерно так:
ostream &operator<<(ostream &s, ios_base& (*m)(ios_base &)) {
return m(s);
}
(Я могу ошибаться, я никогда не смотрел на реализацию, но общая идея состоит в том, что оператор вызывает функцию манипулятора, а манипулятор (ключ в названии) манипулирует потоком).
std::hex
устанавливает флаг формата std::ios::hex
для своего параметра. Затем в вашем operator<<(int)
переопределении, если он у вас есть, проверьте флаги формата, вызвав flags()
.
3) Манипуляторы, принимающие параметры, также являются функциями, но их типы возврата не определены, то есть это зависит от реализации. Глядя на мой заголовок gcc iomanip
, setw
возвращает _Setw
, setprecision
возвращает _Setprecision
и так далее. Библиотека Apache делает это по-другому , больше похоже на манипуляторы без аргументов. Единственное, что вы можете переносить с помощью параметризованных манипуляторов, это применять их к iostream с operator<<
, у них нет определенных функций-членов или собственных операторов.
Так же, как и hex
, для обработки setw
вы должны наследовать от std::ios_base
, полагаться на реализацию operator<<
, предоставленную вашей библиотекой, затем, когда вы придете к форматированию ваших данных, проверьте свою собственную ширину, точность и т. д., используя функции width()
, precision()
и т. д., ios_base
.
Тем не менее, если по какой-то причудливой причине вам необходимо перехватить стандарт operator<<
для этих манипуляторов, вы, вероятно, могли бы что-то связать вместе по следующим направлениям:
template <typename SManip>
mystream &operator<<(mystream &s, SManip m) {
stringstream ss;
// set the state of ss to match that of s
ss.width(s.width());
ss.precision(s.precision());
// etc
ss << m;
// set the state of s to match that of ss
s.width(ss.width());
s.precision(ss.precision());
// etc
return s;
}
Хотя я считаю это уловкой. Вы не должны вмешиваться в потоковые манипуляторы, просто дайте базовому классу поработать и посмотрите на результаты.