Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
dimcoder
Полярный
 Аватар для dimcoder
449 / 422 / 66
Регистрация: 11.09.2011
Сообщений: 1,108
08.02.2012, 11:51     Не понимаю манипуляторы. Как они работают? #1
Здравствуйте. Столкнулся с непониманием манипуляторов. Вот код:

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)
Прошу объяснить, спасибо.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.02.2012, 11:51     Не понимаю манипуляторы. Как они работают?
Посмотрите здесь:

C++ манипуляторы
манипуляторы C++
C++ Манипуляторы в С++
C++ Что такое "bool " и #include <algorithm>? Кто знает , как они работают ?
Манипуляторы. От С к С++ C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
08.02.2012, 11:57     Не понимаю манипуляторы. Как они работают? #2
C++
1
 cout.operator <<( tab );
Так понятнее?
dimcoder
Полярный
 Аватар для dimcoder
449 / 422 / 66
Регистрация: 11.09.2011
Сообщений: 1,108
08.02.2012, 12:09  [ТС]     Не понимаю манипуляторы. Как они работают? #3
Цитата Сообщение от villu Посмотреть сообщение
Так понятнее?
Не совсем. Пример конечно работает, но не понимаю почему. Ведь оно по моей идее должно преобразываться в
C++
1
operator<<(cout,tab);
Что получается, оператор << не перегружается здесь что ли?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
08.02.2012, 12:23     Не понимаю манипуляторы. Как они работают? #4
dimcoder, для потоков вывода определён оператор <<, который принимает указатель на функцию. В теле он просто-напросто вызывает эту функцию и возвращает результат её выполнения.

Добавлено через 41 секунду
Цитата Сообщение от dimcoder Посмотреть сообщение
Ведь оно по моей идее должно преобразываться в
Нет, оно рассматривается компилятором так, как указал villu.
dimcoder
Полярный
 Аватар для dimcoder
449 / 422 / 66
Регистрация: 11.09.2011
Сообщений: 1,108
08.02.2012, 12:32  [ТС]     Не понимаю манипуляторы. Как они работают? #5
Цитата Сообщение от 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&))
}
Или как он/они все точно выглядит? Где их точно можно посмотреть?
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
08.02.2012, 12:36     Не понимаю манипуляторы. Как они работают? #6
который принимает указатель на функцию.
Именно. Причем функцию, которая принимает
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
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
08.02.2012, 12:42     Не понимаю манипуляторы. Как они работают? #7
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&
Это я как-то само собой подразумевал, иначе ответом на вопрос это не являлось бы.
dimcoder
Полярный
 Аватар для dimcoder
449 / 422 / 66
Регистрация: 11.09.2011
Сообщений: 1,108
08.02.2012, 12:52  [ТС]     Не понимаю манипуляторы. Как они работают? #8
silent_1991,
villu, спасибо за ответы, но пока остались вопросы.

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

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

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

Цитата Сообщение от villu Посмотреть сообщение
В этих случаях будет вызван другой вариант вызова operator << (). Скорее всего, с (void *) (может зависеть от реализации STL)
У меня ошибку пишет.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
08.02.2012, 13:00     Не понимаю манипуляторы. Как они работают? #9
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/45fd87...d17d153abe3179

Добавлено через 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;
}
dimcoder
Полярный
 Аватар для dimcoder
449 / 422 / 66
Регистрация: 11.09.2011
Сообщений: 1,108
08.02.2012, 13:49  [ТС]     Не понимаю манипуляторы. Как они работают? #10
Спасибо большое за хороший пример. Вроде понял.
Остался вопрос, как реализован setprecision(int)
C++
1
2
3
#include <iomanip>
//...
cout << setprecision(3) << 3.234;
http://liveworkspace.org/code/27e6f5...e81da1cdbae12f

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

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

Хотя врядли получиться, ведь приоритет слева направо и сначала вызовется cout.operator<< (multiplyByTen).
Я прав?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
08.02.2012, 13:52     Не понимаю манипуляторы. Как они работают? #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
  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; 
    }
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
08.02.2012, 14:11     Не понимаю манипуляторы. Как они работают? #12
Ой говнокод говнокодистый какой-то... Но работает.
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/6b1e12...d89985b8645862

Главное - не пытаться ничего выводить прямо в multiply_by_ten, минуя поток... А то неприятно выводить что-то по нулевому адресу, считая его адресом потока
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
08.02.2012, 14:18     Не понимаю манипуляторы. Как они работают? #13
А как сделать, чтобы на 10 умножались все последующие числа, а не только первое?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
08.02.2012, 14:31     Не понимаю манипуляторы. Как они работают? #14
I.M., а вот так вряд ли получится сделать, тут, скорее всего, действительно надо быть другом потока...
dimcoder
Полярный
 Аватар для dimcoder
449 / 422 / 66
Регистрация: 11.09.2011
Сообщений: 1,108
08.02.2012, 14:31  [ТС]     Не понимаю манипуляторы. Как они работают? #15
Цитата Сообщение от silent_1991 Посмотреть сообщение
Ой говнокод говнокодистый какой-то...
Не, ну после вырезки из iomanip от forever - ваш код для меня - луч солнца в темном лесу.

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

http://liveworkspace.org/code/c57a2d...3c5dcf9a7c5073
AzaKendler
 Аватар для AzaKendler
214 / 116 / 9
Регистрация: 30.05.2011
Сообщений: 1,772
08.02.2012, 14:35     Не понимаю манипуляторы. Как они работают? #16
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?";
вывод
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.02.2012, 15:50     Не понимаю манипуляторы. Как они работают?
Еще ссылки по теме:

Find, replace Как они работают? C++
C++ Виртуальные функции, таблицы виртуальных методов, как они работают?
Четыре комбайна работают с заданной производительностью, определить сколько они собрали зерновых C++

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

Или воспользуйтесь поиском по форуму:
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
08.02.2012, 15:50     Не понимаю манипуляторы. Как они работают? #17
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/24cc96...f7575612280b8a

Добавлено через 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/b1e1e8...daa6a9d0809b32
Yandex
Объявления
08.02.2012, 15:50     Не понимаю манипуляторы. Как они работают?
Ответ Создать тему

Метки
Манипуляторы
Опции темы

Текущее время: 03:32. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru