Перегруженный оператор принимает указатель функции в качестве параметра, как мне получить аргументы указателя функции

у меня есть перегруженный оператор ‹‹, пытающийся заставить его работать так

mystream<<hex<<10;

у меня перегруженный метод

mytream& operator<<(ios_base& (*m) ios_base&)

Это вызывается всякий раз, когда встречается шестнадцатеричный, потому что параметр, переданный в методе, является указателем функции того же типа, что и шестнадцатеричный, или как некоторые другие манипуляторы вывода, такие как dec, oct.

у меня две проблемы

1) как мне получить параметр, с которым будет работать шестнадцатеричный код, в этом примере 10

2) откуда я знаю, что оператор ‹‹ вызывается для шестнадцатеричного, а не для другой функции манипулятора, такой как oct и dec

Спасибо


person Kazoom    schedule 16.07.2009    source источник


Ответы (5)


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;
}

Хотя я считаю это бредом. На самом деле вы не должны вмешиваться в манипуляторы потока, просто позвольте вашему базовому классу выполнять работу и просматривать результаты.

person Steve Jessop    schedule 16.07.2009
comment
спасибо, можете ли вы помочь с тем, как можно обрабатывать манипуляторы, которые принимают аргументы, такие как setw и setprecesion - person Kazoom; 01.10.2009
comment
Позвоните width() и precision(), а также flags(). Подробности выше. - person Steve Jessop; 01.10.2009

Когда operator<< вызывается с hex или oct или dec, установите флаг в вашем объекте mystream. Когда operator<< вызывается с числом, проверьте, установлены ли какие-либо из этих флагов. Если это так, преобразуйте число в шестнадцатеричное/восьмеричное/десятичное и отобразите его.

person Zifre    schedule 16.07.2009
comment
это рекурсивный ответ. Когда оператор ‹‹ вызывается с шестнадцатеричным, восьмеричным или десятичным значением, установите флаг в вашем объекте mystream, второй вопрос: как узнать, какая из этих функций вызывается? преобразовать число в шестнадцатеричное/восьмеричное/десятичное и отобразить его. как мне получить это число в моей перегруженной операторной функции, это первый вопрос - person Kazoom; 16.07.2009
comment
Вы должны получить число в другой перегруженной операторной функции, которая получает int - person e.tadeu; 17.07.2009

Отвечая на ваш второй вопрос, параметр m является указателем на функцию манипулятора. Вы можете проверить, что оно не равно нулю, а затем вызвать эту функцию, передав *this. hex() так же просто, как установить флаг в переданном объекте потока, как предложил Зифре. Затем при обработке целого числа проверьте, установлен ли флаг в объекте потока, и выведите соответственно.

Вот как стандартная библиотека реализует свои функции манипулятора.

person Nick Meyer    schedule 16.07.2009

В вашем примере hex работает (изменяет состояние) с потоком, а не со следующими параметрами. hex не имеет понятия и не имеет отношения к другим вызовам ‹‹.

Глядя на то, как реализованы другие манипуляторы ввода-вывода, можно многое прояснить.

person luke    schedule 16.07.2009