C++. Сборник рецептов
Шрифт:
Во-первых, вам необходимо определить временный класс, который делал бы всю работу. Для простоты предположим, что вам требуется написать манипулятор с именем
setWidth
, который делает то же самое, что и setw
. Временная структура, которую вам необходимо построить, будет выглядеть примерно так. class WidthSetter {
public:
WidthSetter(int n) : width_(n) {}
void operator(ostream& os) const {os.width(width_);}
private:
int width_;
};
Этот
operator
вызывается с аргументом потока, установите ширину для потока в значение, в какое она была установлена при инициализации этого объекта. В результате мы получим WidthSetter
, сконструированный одной функцией и используемый другой. Ваш манипулятор конструирует эту функцию, и это будет выглядеть следующим образом. WidthSetter setWidth(int n) {
return(WidthSetter(n)); // Возвращает инициализированный объект
}
Эта функция всего лишь возвращает объект
WidthSetter
, инициализированный целым значением. Этот манипулятор вы будете использовать в строке операторов operator<<
следующим образом. myostream << setWidth(20) << "banana";
Но этого недостаточно, потому что
setWidth
просто возвращает объект WidthSetter
; operator<<
не будет знать, что с ним делать. Вам придется перегрузить operator<<
, чтобы он знал, как управлять объектом WidthSetter
: ostream& operator<<(ostream& os, const WidthSetter& ws) {
ws(os); // Передать поток объекту ws
return(os); // для выполнения реальной работы
}
Это решает проблему, но не в общем виде. Вам не захочется писать класс типа
WidthSetter
для каждого вашего манипулятора, принимающего аргумент (возможно, вы это и делаете, но были бы не против поступить по-другому), поэтому лучше использовать шаблоны и указатели функций для получения привлекательной, обобщенной инфраструктуры, на базе которой вы можете создавать любое количество манипуляторов. Пример 10.5 содержит класс ManipInfra
и версию operator<<
, использующую аргументы шаблона для работы с различными типами символов, которые может содержать поток, и с различными типами аргументов, которые могут быть использованы манипулятором потока. Пример 10.5. Инфраструктура манипуляторов
#include <iostream>
#include <string>
using namespace std;
// ManipInfra - это небольшой промежуточный класс, который помогает
// создавать специальные манипуляторы с аргументами. Вызывайте его
// конструктор с предоставлением указателя функции
и значения из основной
// функции манипулятора
// Указатель функции должен ссылаться на вспомогательную функцию, которая
// делает реальную работу. См. примеры ниже
template<typename T, typename C>
class ManipInfra {
public:
ManipInfra(basic_ostream<C>& (*pFun) (basic_ostream<C>&, T), T val) :
manipFun_(pFun), val_(val) {}
void operator(basic_ostream<C>& os) const {
manipFun_(os, val_);
} // Вызовите функцию, задавая ее указатель и
private: // передавая ей поток и значение
T val_;
basic_ostream<С>& (*manipFun_) (basic_ostream<C>&, T);
};
template<typename T, typename C>
basic_ostream<C>& operator<<(basic_ostream<C>& os,
const ManipInfra<T, C>& manip) {
manip(os);
return(os);
}
// Вспомогательная функция, которая вызывается в итоге в классе ManipInfra
ostream& setTheWidth(ostream& os, int n) {
os.width(n);
return(os);
}
// Собственно функция манипулятора. Именно она используется в клиентском
// программном коде
ManipInfra<int, char> setWidth(int n) {
return(ManipInfra<int, char>(setTheWidth, n));
}
// Ещё одна вспомогательная функция, которая принимает аргумент типа char
ostream& setTheFillChar(ostream& os, char с) {
os.fill(c);
return(os);
}
ManipInfra<char, char> setFill(char c) {
return(ManipInfra<char, char>(setTheFillChar, c));
}
int main {
cout << setFill('-')
<< setWidth(10) << right << "Proust\n";
}
Если последовательность событий при работе этого класса все же остается неясной, я советую прогнать пример 10.5 через отладчик. Увидев его реальную работу, вы все поймете.
Поделиться:
Популярные книги
Хозяин Теней 3
3. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Контракт на материнство
Любовные романы:
современные любовные романы
5.00
рейтинг книги
На границе империй. Том 10. Часть 3
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
Эволюционер из трущоб
1. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Идеальный мир для Лекаря 5
5. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Боец с планеты Земля
1. Потерявшийся
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
Бастард Императора. Том 5
5. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Правильный попаданец
1. Мент
Фантастика:
альтернативная история
5.75
рейтинг книги
Морской волк. 1-я Трилогия
1. Морской волк
Фантастика:
альтернативная история
8.71
рейтинг книги
Его огонь горит для меня. Том 2
2. Мир Карастели
Фантастика:
юмористическая фантастика
5.40
рейтинг книги
Блуждающие огни 4
4. Блуждающие огни
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Жена воина, или любовь на выживание
3. Право сильнейшего
Фантастика:
фэнтези
8.98
рейтинг книги
Локки 4 Потомок бога
4. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 19
19. Лекарь
Фантастика:
юмористическое фэнтези
аниме
5.00