Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
Полярный
 Аватар для dimcoder
477 / 449 / 158
Регистрация: 11.09.2011
Сообщений: 1,156

Не понимаю манипуляторы. Как они работают?

08.02.2012, 11:51. Показов 2333. Ответов 16

Студворк — интернет-сервис помощи студентам
Здравствуйте. Столкнулся с непониманием манипуляторов. Вот код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdlib>
#include <iostream>
 
using namespace std;
 
ostream& tab (ostream& output)          //Manipulator
{
    return output << "\t";
}
 
int main(int argc, char *argv[])
{
    cout << tab;
    cout << "Hello";       //How (?!?!) does it converts to: tab(cout), if it really does?
    //...................
    cout << endl;
    //...................
    tab(cout);             //I understand
    cout << "Hello ";
    system("PAUSE > NULL");
    return EXIT_SUCCESS;
}
Не понятно как cout << tab преобразуется в tab(cout).
Да и вообще не понятно, скажем как работает cout.precision(int)
Прошу объяснить, спасибо.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
08.02.2012, 11:51
Ответы с готовыми решениями:

Для чего нужны сужающие преобразования как они работают и на сколько они важны?
Я читаю одну книгу и застрял на одной теме &quot;Преобразования&quot;, и там есть такой вот код double х {2.7}; int у {х}; // Ошибка : double...

Find, replace Как они работают?
#include &lt;iostream&gt; #include &lt;string&gt; using namespace std; int main(){ string s1; getline(cin,s1); string s2; ...

Подскажите что такое классы и как они работают
Значит, написал я программу, отправил учителю, а в ответ получил: 1. Программа по-прежнему не имеет определенного класса, описывающего...

16
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
08.02.2012, 11:57
C++
1
 cout.operator <<( tab );
Так понятнее?
1
Полярный
 Аватар для dimcoder
477 / 449 / 158
Регистрация: 11.09.2011
Сообщений: 1,156
08.02.2012, 12:09  [ТС]
Цитата Сообщение от villu Посмотреть сообщение
Так понятнее?
Не совсем. Пример конечно работает, но не понимаю почему. Ведь оно по моей идее должно преобразываться в
C++
1
operator<<(cout,tab);
Что получается, оператор << не перегружается здесь что ли?
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
08.02.2012, 12:23
dimcoder, для потоков вывода определён оператор <<, который принимает указатель на функцию. В теле он просто-напросто вызывает эту функцию и возвращает результат её выполнения.

Добавлено через 41 секунду
Цитата Сообщение от dimcoder Посмотреть сообщение
Ведь оно по моей идее должно преобразываться в
Нет, оно рассматривается компилятором так, как указал villu.
1
Полярный
 Аватар для dimcoder
477 / 449 / 158
Регистрация: 11.09.2011
Сообщений: 1,156
08.02.2012, 12:32  [ТС]
Цитата Сообщение от silent_1991 Посмотреть сообщение
определён оператор <<
}{м, то есть прототип функции вызова функций для cout записан так:
C++
1
2
3
4
5
6
7
class basic_ostream
{
   public:
   //blablabla
   void operator<< ((ostream&) * (ostream&));
   void operator<< ((const ostream &) *(ostream&))
}
Или как он/они все точно выглядит? Где их точно можно посмотреть?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
08.02.2012, 12:36
который принимает указатель на функцию.
Именно. Причем функцию, которая принимает
ostream& и возвращает ostream&

Для интереса попробуй сделать в том же коде

C++
1
wcout << tab; //
а после измени функцию так
C++
1
2
3
ostream& tab ( ostream& output, int t = 10 ) { ... }
....
cout << tab;
В этих случаях будет вызван другой вариант вызова operator << (). Скорее всего, с (void *) (может зависеть от реализации STL)

Добавлено через 2 минуты
Цитата Сообщение от dimcoder Посмотреть сообщение
Где их точно можно посмотреть?
в файле ostream пользуемой библиотеки. в студии, например тут c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\ostream
1
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
08.02.2012, 12:42
dimcoder, реализация gcc:
C++
1
2
3
4
5
6
7
8
      __ostream_type&
      operator<<(__ostream_type& (*__pf)(__ostream_type&))
      {
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // DR 60. What is a formatted input function?
    // The inserters for manipulators are *not* formatted output functions.
    return __pf(*this);
      }
Добавлено через 4 минуты
Цитата Сообщение от villu Посмотреть сообщение
Причем функцию, которая принимает
ostream& и возвращает ostream&
Это я как-то само собой подразумевал, иначе ответом на вопрос это не являлось бы.
1
Полярный
 Аватар для dimcoder
477 / 449 / 158
Регистрация: 11.09.2011
Сообщений: 1,156
08.02.2012, 12:52  [ТС]
silent_1991,
villu, спасибо за ответы, но пока остались вопросы.

Цитата Сообщение от silent_1991 Посмотреть сообщение
Причем функцию, которая принимает
ostream& и возвращает ostream&
А если я не хочу каскадной записи? Вот допустим так:
http://liveworkspace.org/code/... bb26138fdd

Откуда здесь 1?

И как работает функция setw(int) из iomanip? Как создать такой манипулятор?
C++
1
cout << setw(6) << 289;

Цитата Сообщение от villu Посмотреть сообщение
В этих случаях будет вызван другой вариант вызова operator << (). Скорее всего, с (void *) (может зависеть от реализации STL)
У меня ошибку пишет.
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
08.02.2012, 13:00
dimcoder, тут тоже, скорее всего, вызывается версия с void *, потому что ваш "манипулятор" не соответствует сигнатуре функции, указатель на которую принимает остримовский оператор <<, т.е. манипулятора здесь не получается.

Цитата Сообщение от dimcoder Посмотреть сообщение
setw(int)
Тут уже другая схема, тут всё завязано на классах. Вот пример манипулятора, который выводит переданное ему число табуляций:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
 
class tab
{
public:
    tab(size_t count):
    m_count(count)
    {
    }
 
    friend std::ostream& operator<<(std::ostream& stream, const tab& tab_manip)
    {
        for (size_t i = 0; i < tab_manip.m_count; ++i)
            stream << '\t';
 
        return stream;
    }
 
private:
    size_t m_count;
};
 
int main()
{
    std::cout << tab(3) << "Hello" << std::endl;
 
    return 0;
}
http://liveworkspace.org/code/... 153abe3179

Добавлено через 2 минуты
dimcoder, вот так, если сильно не хочется каскадной записи:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
 
class tab
{
public:
    tab(size_t count):
    m_count(count)
    {
    }
 
    friend /*std::ostream&*/ void operator<<(std::ostream& stream, const tab& tab_manip)
    {
        for (size_t i = 0; i < tab_manip.m_count; ++i)
            stream << '\t';
 
        //return stream;
    }
 
private:
    size_t m_count;
};
 
int main()
{
    //std::cout << tab(3) << "Hello" << std::endl;
 
    std::cout << tab(3);
    std::cout << "Hello" << std::endl;
 
    return 0;
}
1
Полярный
 Аватар для dimcoder
477 / 449 / 158
Регистрация: 11.09.2011
Сообщений: 1,156
08.02.2012, 13:49  [ТС]
Спасибо большое за хороший пример. Вроде понял.
Остался вопрос, как реализован setprecision(int)
C++
1
2
3
#include <iomanip>
//...
cout << setprecision(3) << 3.234;
http://liveworkspace.org/code/... a1cdbae12f

Я так понимаю класс содержащий setprecision является другом cout'a?

Или все таки можно описать класс чтобы можно было делать так:
C++
1
2
myClass multyplyByTen;
cout << multiplyByTen << 3;  //Ну типа умножили на десять и вывели
c выводом 30

Хотя врядли получиться, ведь приоритет слева направо и сначала вызовется cout.operator<< (multiplyByTen).
Я прав?
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
08.02.2012, 13:52
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  struct _Setprecision { int _M_n; };
 
  /**
   *  @brief  Manipulator for @c precision.
   *  @param  n  The new precision.
   *
   *  Sent to a stream object, this manipulator calls @c precision(n) for
   *  that object.
  */
  inline _Setprecision 
  setprecision(int __n)
  { return { __n }; }
 
  template<typename _CharT, typename _Traits>
    inline basic_istream<_CharT, _Traits>& 
    operator>>(basic_istream<_CharT, _Traits>& __is, _Setprecision __f)
    { 
      __is.precision(__f._M_n); 
      return __is; 
    }
 
  template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>& 
    operator<<(basic_ostream<_CharT, _Traits>& __os, _Setprecision __f)
    { 
      __os.precision(__f._M_n); 
      return __os; 
    }
1
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
08.02.2012, 14:11
Ой говнокод говнокодистый какой-то... Но работает.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
 
class MultiplyByTenManip
{
public:
    MultiplyByTenManip(std::ostream *stream = 0):
    m_stream(stream)
    {
    }
 
    template<typename T>
    std::ostream& operator <<(const T& value)
    {
        return *m_stream << value * 10;
    }
 
    friend MultiplyByTenManip operator <<(std::ostream& stream, const MultiplyByTenManip& manip);
 
private:
    std::ostream *m_stream;
};
 
MultiplyByTenManip operator <<(std::ostream& stream, const MultiplyByTenManip&)
{
    return MultiplyByTenManip(&stream);
}
 
MultiplyByTenManip multiply_by_ten;
 
int main()
{
    std::cout << multiply_by_ten << 42 << std::endl;
 
    return 0;
}
http://liveworkspace.org/code/... 85b8645862

Главное - не пытаться ничего выводить прямо в multiply_by_ten, минуя поток... А то неприятно выводить что-то по нулевому адресу, считая его адресом потока
2
 Аватар для I.M.
576 / 559 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
08.02.2012, 14:18
А как сделать, чтобы на 10 умножались все последующие числа, а не только первое?
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
08.02.2012, 14:31
I.M., а вот так вряд ли получится сделать, тут, скорее всего, действительно надо быть другом потока...
0
Полярный
 Аватар для dimcoder
477 / 449 / 158
Регистрация: 11.09.2011
Сообщений: 1,156
08.02.2012, 14:31  [ТС]
Цитата Сообщение от silent_1991 Посмотреть сообщение
Ой говнокод говнокодистый какой-то...
Не, ну после вырезки из iomanip от forever - ваш код для меня - луч солнца в темном лесу.

Цитата Сообщение от I.M. Посмотреть сообщение
А как сделать, чтобы на 10 умножались все последующие числа, а не только первое?
Правда потом х выведешь что нибудь другое "каскадом"

http://liveworkspace.org/code/... cf9a7c5073
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
08.02.2012, 14:35
I.M., создавать свой класс производный от ostream и подсовывать его операторам <<, которые придется перегрузить. ну а внутри класса уже скидывать в cout.

т.е. cout<<multi(10)<<1<<2<<3;

где то я делал пример с шифрованием потока. шас поищу.

Добавлено через 2 минуты
ВОТ ссылка на манипулятор криптующий поток с ключом char*, криптуется весь последующий вывод, до тех пор пока криптование не будет отменено


C++
1
cout<<crypto_in("346767")<<" Hellow friend,how are you?"<<stop_crypt<<" Hellow friend, how are you?";
вывод
1
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
08.02.2012, 15:50
AzaKendler, мне тоже в голову пришёл вариант с "операторными скобками", но без наследования. Сейчас попробую накидать...

Добавлено через 6 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
 
class MultiplyByTenManipException : std::exception
{
public:
    virtual ~MultiplyByTenManipException() throw()
    {
    }
 
    virtual const char *what() const throw()
    {
        return "impossible output the value bypassing stream";
    }
};
 
class MultiplyByTenEndManip
{
};
 
class MultiplyByTenBeginManip
{
public:
    MultiplyByTenBeginManip(std::ostream *stream = 0):
    m_stream(stream)
    {
    }
    
    template<typename T>
    MultiplyByTenBeginManip operator <<(T value)
    {
        if (m_stream == 0)
            throw MultiplyByTenManipException();
 
        *m_stream << value * 10;
 
        return *this;
    }
 
    MultiplyByTenBeginManip operator <<(const char *str)
    {
        *m_stream << str;
 
        return *this;
    }
 
    std::ostream& operator <<(const MultiplyByTenEndManip&)
    {
        return *m_stream;
    }
 
    friend MultiplyByTenBeginManip operator <<(std::ostream& stream, const MultiplyByTenBeginManip& manip)
    {
        return MultiplyByTenBeginManip(&stream);
    }
 
private:
    std::ostream *m_stream;
};
 
MultiplyByTenBeginManip multiply_by_ten_begin;
MultiplyByTenEndManip multiply_by_ten_end;
 
int main()
{
    std::cout << multiply_by_ten_begin << 42 << "  " << 3.7 << multiply_by_ten_end << std::endl;
 
    return 0;
}
http://liveworkspace.org/code/... 5612280b8a

Добавлено через 7 минут
Ну и под конец кретиффчег - манипулятор, применяющий к последовательности значений (вплоть до "закрывающего" манипулятора) некоторую функцию (правда получилось не совсем так, как хотелось, ну да ладно):

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <iostream>
 
class TransformManipulatorException : std::exception
{
public:
    virtual ~TransformManipulatorException() throw()
    {
    }
 
    virtual const char *what() const throw()
    {
        return "impossible output the value bypassing stream";
    }
};
 
class TransformManipulatorEnd
{
};
 
template<typename Function>
class TransformManipulatorBegin;
 
template<typename Function>
TransformManipulatorBegin<Function> operator <<(std::ostream& stream,
    const TransformManipulatorBegin<Function>& manip);
 
template<typename Function>
class TransformManipulatorBegin
{
public:
    TransformManipulatorBegin(Function *func, std::ostream *stream = 0):
    m_func(func),
    m_stream(stream)
    {
    }
    
    template<typename T>
    TransformManipulatorBegin operator <<(T value)
    {
        if (m_stream == 0)
            throw TransformManipulatorException();
 
        *m_stream << m_func(value);
 
        return *this;
    }
    
    TransformManipulatorBegin<Function> operator <<(const char *str)
    {
        if (m_stream == 0)
            throw TransformManipulatorException();
 
        *m_stream << str;
 
        return *this;
    }
    
    std::ostream& operator <<(const TransformManipulatorEnd&)
    {
        return *m_stream;
    }
 
    friend TransformManipulatorBegin<Function> operator << <Function>(std::ostream& stream,
        const TransformManipulatorBegin<Function>& manip);
 
private:
    Function *m_func;
    std::ostream *m_stream;
};
 
template<typename Function>
TransformManipulatorBegin<Function> operator <<(std::ostream& stream,
    const TransformManipulatorBegin<Function>& manip)
{
    return TransformManipulatorBegin<Function>(manip.m_func, &stream);
}
 
int func(int val)
{
    return val * 10;
}
 
double func2(double val)
{
    return val / 2.0;
}
 
int main()
{
    std::cout << TransformManipulatorBegin<int(int)>(func)
                 << 10 << "  " << 42
                 << TransformManipulatorEnd()
              << std::endl;
    
    std::cout << TransformManipulatorBegin<double(double)>(func2)
                 << 10.8 << "  " << 42.22
                 << TransformManipulatorEnd()
              << std::endl;
 
    return 0;
}
http://liveworkspace.org/code/... a9d0809b32
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.02.2012, 15:50
Помогаю со студенческими работами здесь

Виртуальные функции, таблицы виртуальных методов, как они работают?
подскажите пожалуйста,где лучше посмотреть про начинку виртуальных функций,т.е. про таблицы виртуальных методов и как они работают. Заранее...

Постигаю c++ и не могу в здешние циклы, а ещё в тип char кто знает как они работают подскажите
Есть сия код. Массив 7 столбцов на 5 строк (5 доярок(строки), 6 дней(столбцы), и 7 столбец для занесения в него среднего числа) ...

Что такое "bool " и #include <algorithm>? Кто знает , как они работают ?
Вот код: #include &quot;stdafx.h&quot; #include &lt;algorithm&gt; #include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; bool...

Энкодеры. Как они работают?
Есть пульт управления на 433Мгц. Первая кнопка включает/выключает первую лампу, вторая включает/выключает вторую лампу и т.д. Всего кнопок...

не понимаю как реализовать одновременную работу процессов, как сделать так, что бы они одновременно проверяли доступен ресурс или нет
Здравствуйте! Подскажите, как можно одновременно запустить проверку условия. Я пытаюсь написать программу решения проблемы обедающих...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
Установка Emscripten SDK (emsdk) и CMake на Windows для сборки C и C++ приложений в WebAssembly (Wasm)
8Observer8 30.01.2026
Чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. Система контроля версиями Git. . .
Подключение Box2D v3 к SDL3 для Android: физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru