Страница 2 из 3

Re: Потомок std::ofstream, не работает манипулятор

Добавлено: 05 дек 2015, 12:03
Сионист

Код: Выделить всё

typedef std: :o stream &(*TManipulator)(std: :o stream  &Stream);
class TMyStream : public std: :o fstream
{
 public:
 ...
  TMyStream &operator << (const TManipulator Manipulator)
  {
   Manipulator(*((std: :o fstream*)this));
   return *this;
  }
 ...
};

Re: Потомок std::ofstream, не работает манипулятор

Добавлено: 05 дек 2015, 12:17
Romeo
Если честно, я на эту тему в своё время не обратил внимания, просто по верхам глянул. Сейчас посмотрел внимательно на код и удивился, почему ты ожидал, что он будет компилиться, ведь у тебя операторы перегружены только для указателей на символы, а для манипулятора - нет.

А решение вообще убило. Определить оператор для функции, принимающей стандартный стрим. А зачем так изголяться, расскажи? Может я чего-то не понимаю? Что мешает определить оператор, принимающий стрим, который возвращает манипулятор? Ты понимаешь, что твоё текущее решение запрещает клеить операторы << после манипулятора, не говоря уже о том, что это костыль-костыльный сам по себе? Это называется "как сделать очевидную вещь не очевидной".

И этот человека рассуждает о теории множеств и о том, что студенческий оператора "минус" нарушает семантику операции... а у тебя здесь семантика ни разу не нарушена, как ты думаешь? :)

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

Добавлено: 05 дек 2015, 13:19
Сионист
Romeo писал(а):Сейчас посмотрел внимательно на код и удивился, почему ты ожидал, что он будет компилиться, ведь у тебя операторы перегружены только для указателей на символы, а для манипулятора - нет.
И? А почему он не наследуется?
Romeo писал(а):А решение вообще убило. Определить оператор для функции, принимающей стандартный стрим. А зачем так изголяться, расскажи? Может я чего-то не понимаю? Что мешает определить оператор, принимающий стрим, который возвращает манипулятор?
А зачем мне писать свои манипуляторы? Они всё равно ничего нового не делают.
Romeo писал(а):Ты понимаешь, что твоё текущее решение запрещает клеить операторы << после манипулятора, не говоря уже о том, что это костыль-костыльный сам по себе? Это называется "как сделать очевидную вещь не очевидной".
Это с какого? Оператор принимает и возвращает мой класс. Если Вы не в состоянии даже отличить синтаксис перегрузки от завёрнутого в тело применения функции над предком, то какого берётесь оценивать чьи то знания? Тест, кстати, тоже говорит от обратном.

Re: Потомок std::ofstream, не работает манипулятор

Добавлено: 05 дек 2015, 13:48
Romeo
Сионист писал(а):И? А почему он не наследуется?
Потому, что так сказал дедушка Страуструп. Это закреплено стандартом, который ты никак не хочешь прочесть.
Сионист писал(а):А зачем мне писать свои манипуляторы? Они всё равно ничего нового не делают.
А где я написал, что нужно написать свой манипулятор? Прочти ещё раз моё сообщение. Там было написано об операторе, принимающем стрим (!), который возвращает манипулятор.
Сионист писал(а):Это с какого? Оператор принимает и возвращает мой класс. Если Вы не в состоянии даже отличить синтаксис перегрузки от завёрнутого в тело применения функции над предком, то какого берётесь оценивать чьи то знания? Тест, кстати, тоже говорит от обратном..
Мне кажется именно ты не разбираешься в синтаксисе. Можешь мне объяснить, что обозначает вот это объявление?

Код: Выделить всё

typedef std: :o stream &(*TManipulator)(std: :o stream  &Stream);

Давай я расшифрую, так как у тебя с этим проблемы, судя по последнему сообщению. Тут объявляется тип. Этот тип является указателем на функцию, которая принимает ссылку на стандратный стрим и возвращает ссылку на стандратный стрим. Далее смотрим сюда:

Код: Выделить всё

TMyStream &operator << (const TManipulator Manipulator)
Это оператор, который принимает указатель на функцию (а совсем не твой класс, как ты пишешь). Не вдаваясь даже в то, что const тут бесполезен, перейдём к вызову этого оператора.

Код: Выделить всё

TMyStream stream;
stream << std::endl;
Фактически в этом месте MinGW подставляет тебе перед std::endl оператор взятия адреса, то есть код выглядит вот так:

Код: Выделить всё

TMyStream stream;
stream << &std::endl;
Как следствие, оператор получает манипулятор, как указатель на функцию (коим он, по сути, и является) и потом, внутри себя вызывает эту функцию:

Код: Выделить всё

Manipulator(*((std: :o fstream*)this));
Это работает лишь потому, что у тебя MinGW. Не все компиляторы подставляют автоматически амперсанд в том месте, где нужен указатель на функцию, об этом мы с тобой разговаривали пару месяцев назад в другой теме.

Что ты теряешь? При таком подходе ты не можешь приклеить к манипулятору справа через << выражения, как это все привыкли делать. Не говоря уже о том, что это просто ужасное решение с архитектурной точки зрения.

А теперь внимательно прочти мой предыдущий пост ещё раз, и ты сможешь понять, как нужно поменять код, чтобы всё было хорошо.

Добавлено: 05 дек 2015, 14:52
Сионист
Romeo писал(а):Потому, что так сказал дедушка Страуструп. Это закреплено стандартом, который ты никак не хочешь прочесть.
Именно там и сказано, что члены предка наследуются. И ни какого амбигуса при именно таком наследовании на поверхности не валялось.
Мне кажется именно ты не разбираешься в синтаксисе. Можешь мне объяснить, что обозначает вот это объявление?
Код cpp:
typedef std: :o stream &(*TManipulator)(std: :o stream &Stream);
Всего лишь тип указателя на функцию, принимающую ссылку на std: :o stream. А
Romeo писал(а): Давай я расшифрую, так как у тебя с этим проблемы, судя по последнему сообщению. Тут объявляется тип. Этот тип является указателем на функцию, которая принимает ссылку на стандратный стрим и возвращает ссылку на стандратный стрим. Далее смотрим сюда:

Код: Выделить всё

TMyStream &operator << (const TManipulator Manipulator)
Это оператор, который принимает указатель на функцию (а совсем не твой класс, как ты пишешь)
Не статические функции-члены и статические операторы-члены имеют ещё один не явный параметр/операнд - экземпляр своего класса, передаваемый по указателю this, от него они и вызываются. В случае не статического оператора-члена этот неявный операнд левый, в случае не статической функции-члена предшествует оператору точка, либо располагается по адресу в указателе, предшествующем оператору минус равно. Так что мой класс оператор тоже принимает. Слева.
Что ты теряешь? При таком подходе ты не можешь приклеить к манипулятору справа через << выражения, как это все привыкли делать. Не говоря уже о том, что это просто ужасное решение с архитектурной точки зрения.
Могу. И даже уже приклеил, дальше даже поставил

Код: Выделить всё

<<std::endl<<std::endl
и ещё раз приклеил оператор <<. Обратите внимание: std: :o fsream принимает и возвращает функция, указатель на которую принят в правом операнде, а сам оператор принимает слева и возвращает мой класс. Так как остальные версии << также возвращают мой класс, то к какой бы из них кто ни прилепил справа

Код: Выделить всё

<<std::ednl
, левый операнд будет экземпляром моего класса и что бы ни кто бы ни прилепил справа к

Код: Выделить всё

<<std::ednl
, левым операндом опять будет экземпляр моего класса. Предок завёрнут только в тело.

Re: Потомок std::ofstream, не работает манипулятор

Добавлено: 05 дек 2015, 16:14
Romeo
Сионист писал(а):Именно там и сказано, что члены предка наследуются. И ни какого амбигуса при именно таком наследовании на поверхности не валялось.
А ничего, что все эти операторы не принадлежат базовому классу, а являются внешними функциями? О каком наследовании может идти речь?
Сионист писал(а): Не статические функции-члены и статические операторы-члены имеют ещё один не явный параметр/операнд - экземпляр своего класса, передаваемый по указателю this, от него они и вызываются. В случае не статического оператора-члена этот неявный операнд левый, в случае не статической функции-члена предшествует оператору точка, либо располагается по адресу в указателе, предшествующем оператору минус равно. Так что мой класс оператор тоже принимает. Слева.
Вот зачем ты это всё написал? Ты бы ещё таблицу умножения сюда втулил, капитан. Я отлично знаю о this, но когда я кому-то говорю, что мой метод что-то принимает, то я всегда имею в виду его ЯВНЫЙ параметр. Ожидал от тебя такой же конструктивной позиции. Вот именно поэтому с тобой очень сложно общаться. Очевидные вещи ты считаешь непонятными, а не очевидные наоборот считаешь очевидными.

Люди, кто-то ещё мог предложить по предыдущему посту человека, что он имел в виду this?
Сионист писал(а): Могу. И даже уже приклеил, дальше даже поставил

Код: Выделить всё

<<std::endl<<std::endl
и ещё раз приклеил оператор <<. Обратите внимание: std: :o fsream принимает и возвращает функция, указатель на которую принят в правом операнде, а сам оператор принимает слева и возвращает мой класс. Так как остальные версии << также возвращают мой класс, то к какой бы из них кто ни прилепил справа

Код: Выделить всё

<<std::ednl
, левый операнд будет экземпляром моего класса и что бы ни кто бы ни прилепил справа к

Код: Выделить всё

<<std::ednl
, левым операндом опять будет экземпляр моего класса. Предок завёрнут только в тело.
Да, тут я не довертел в голове. Действительно, возможность клеить выражения справа не теряется. Но аргумент о том, что это страшный костыль никак не устраняется, к сожалению. Ты разрываешь цепочку операторов самым неожиданным способом (приняв манипулятор, как указатель на функцию). Неожиданность - это одна из самых плохих вещей в проектировании системы. Программист всегда должен действовать по принципу наименьшего удивления, тогда его код будет максимально просто поддерживать.

Чуть позже я предоставлю пример, когда из-за такого кривого подхода у тебя всё станет работать не так, как ожидалось, просто сразу в голове не приходит, а времени уже нет. Отвечу чуть позже вечером.

И по-прежнему призываю всё привести к однородной архитектуре, которая принята стандартом для операторов <<, тогда костыли пропадут сами по себе.

Добавлено: 05 дек 2015, 16:21
Сионист
А ничего, что все эти операторы не принадлежат базовому классу, а являются внешними функциями? О каком наследовании может идти речь?
Функция функцией. Но как она вызывается?

Код: Выделить всё

std: :o fstream f;
...
std::endl(f);
? Нет, обычно не так.

Код: Выделить всё

std: :o fstream f;
...
f<<std::endl;
, а << - оператор-член. И компилятор ругался не на то, что оператора << нет вообще, а на амбигус.
Ты разрываешь цепочку операторов самым неожиданным способом (приняв манипулятор, как указатель на функцию).
А как же он принимается в std: :o fstream? Разве не так?
Ты бы ещё таблицу умножения сюда втулил, капитан. Я отлично знаю о this, но когда я кому-то говорю, что мой метод что-то принимает, то я всегда имею в виду его ЯВНЫЙ параметр. Ожидал от тебя такой же конструктивной позиции. Вот именно поэтому с тобой очень сложно общаться. Очевидные вещи ты считаешь непонятными, а неочевидные наоборот считаешь очевидными. Люди, кто-то ещё мог предложить по предыдущему посту человека, что он имел в виду this?
А ничего, что неявен он лишь в прототипе и теле оператора и вполне явен синтаксисе вызова? Да и словосочетания "явно принимает" не было.

Re: Потомок std::ofstream, не работает манипулятор

Добавлено: 05 дек 2015, 16:28
Romeo
Ну ты бы хоть открыл бы для приличия стандартный хедер и посмотрел, как там выглядит этот оператор. Даже если ты не знаешь, что все потоковые операторы являются внешними (хотя это нужно знать), то открыть код STL и посмотреть, как оно на самом деле - это самое простое, что можно сделать в такой ситуации.

Re: Потомок std::ofstream, не работает манипулятор

Добавлено: 05 дек 2015, 16:50
Absurd
Ну там, к слову сказать, не понимаю кому нужен от потока ввода-вывода какой-то функционал кроме как прочитать 1..N байт/записать N байт. Проверить eof. ioctl() для портов. Ну и для блочных устройств - seek/tell.

iostream же сионист какой-то писал. Бриллиантовое наследование от std::ios зачем-то вкрутили. Потоки ввода-вывода вправо-влево сдвигают. Спроси любого программиста: каков полный интерфейс std::iostream? Если он ответит правильно, то его надо увольнять: он не интересуется теми вещами которые имеют практическую пользу, т.е фронтендом, базами данных, анализом данных, 2D/3D графикой, численным моделированием, сетевыми протоколами итд итп. Он изучает вещи в себе.

Человек и библиотека нашли друг друга.

Добавлено: 05 дек 2015, 16:52
Сионист
Romeo писал(а):Ну ты бы хоть открыл бы для приличия стандартный хедер
Не открывается.
Absurd писал(а):Ну там, к слову сказать, не понимаю кому нужен от потока ввода-вывода какой-то функционал кроме как прочитать 1..N байт/записать N байт. Проверить eof. ioctl() для портов. Ну и для блочных устройств - seek/tell.
Как раз этот функционал к потоку вообще не относится. Наоборот, при выводе в поток, например, целого оператор выводит строчную запись числа, а не байты самого данного. А конкретно этот класс ещё перекодирует выводимые строки из utf-32 в utf-8, умеет выводить PAINTSTUCT, HDC и RECT. При выводе данного любого их этих типов выводятся все его данные-члены, каждый обрамляется своими xml-тегами (открывающим и закрывающим) и они разделяются переводом каретки в начало следующей строки. А сырой вывод байтов - это WiteFile.
Absurd писал(а):Спроси любого программиста: каков полный интерфейс std::iostream? Если он ответит правильно, то его надо увольнять: он не интересуется теми вещами которые имеют практическую пользу, т.е фронтендом, базами данных, анализом данных, 2D/3D графикой, численным моделированием, сетевыми протоколами итд итп. Он изучает вещи в себе.
Тогда откуда ему знать интерфейс std::iosream и даже вообще знать об его существовании?