Перегруженный оператор принимает указатель на функцию в качестве параметра, как получить аргументы указателя на функцию - PullRequest
1 голос
/ 16 июля 2009

у меня перегружен оператор << пытаюсь заставить его работать так </p>

mystream<<hex<<10;

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

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

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

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

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

2) откуда мне знать, что оператор << вызывается для шестнадцатеричной, а не другой функции-манипулятора, такой как oct и dec </p>

Спасибо

Ответы [ 5 ]

7 голосов
/ 17 июля 2009

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

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

0 голосов
/ 16 июля 2009

Вы должны манипулировать ios_base :: flags

http://www.cplusplus.com/reference/iostream/ios_base/flags/

Это то, что делает стандартный гекс.

0 голосов
/ 16 июля 2009

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

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

0 голосов
/ 16 июля 2009

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

Рассмотрение того, как реализованы другие манипуляторы io, будет иметь большое значение для выяснения ситуации.

0 голосов
/ 16 июля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...