Re[3]: variadic
От: rg45 СССР  
Дата: 25.09.23 13:58
Оценка: :)))
Здравствуйте, Sm0ke, Вы писали:

S>ради эксперимента

S>Попробовал этот трюк провернуть с вариадиками, но что-то пошло не так: https://godbolt.org/z/9rdGfzn76

Перед кем ты бисер мечешь? Его от шаблонов корежит, как вампира от чеснока, он макросы использует, только чтоб к шаблонам не прикасаться. А ты ему вариадики.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[8]: Почему нельзя предварительно объявить дружественную ф
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.09.23 14:20
Оценка: :))
Здравствуйте, so5team, Вы писали:

S>Если ваш код не соответствует стандарту, то он запросто может перестать работать при обновлении компилятора.


Теоретически — может. А практически — ни разу не переставал. Он даже компилироваться ни разу не переставал — только новые предупреждения появлялись при /Wall.

Вот только практика показывает, что код, полностью соответствующий определенному стандарту, запросто может перестать компилироваться и/или работать при обновлении компилятора, ориентированного на более новые стандарты, и не поддерживающего старых (по крайней мере, по умолчанию). С этим что будем делать?

Вообще, требование полного соответствия любого кода стандарту — это, грубо говоря, как требование надежной работы изделия в пределах хотя бы всей планеты — и на экваторе, и на полюсах, и в стратосфере, и под водой. Для некоторых изделий это необходимо, но для подавляющего большинства вполне достаточно "разумных условий". Ежели у кого автомобиль, сделанный в Испании, плохо заводится в Якутии или на Аляске, он почему-то не спешит объявлять его "не соответствующими стандарту автомобиля".

S>Но доблести, увы, в этом нет. И у людей, которые набили шишек при переносе кода между vc++, gcc и clang (хотя бы этими тремя), подобная бравада одобрения не вызывает, мягко говоря.


Это не доблесть и не бравада. Это вполне разумный инженерный подход, который еще не так давно преобладал и в C, и в C++, а сейчас продолжает преобладать в большинстве других языков, для которых нет единых стандартов. А вот в C++ из стандарта сделали фетиш.
Re[4]: variadic
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.09.23 14:23
Оценка:
Здравствуйте, rg45, Вы писали:

R>Его от шаблонов корежит, как вампира от чеснока, он макросы использует, только чтоб к шаблонам не прикасаться.


Я не раз подчеркивал, что регулярно применяю шаблоны по их прямому назначению. А то, что вместо вашей любимой SFINAE-магии мне часто удобнее применить макрос, который и проще, и понятнее, а часто еще и компактнее по коду — звиняйте, уж как есть.
Re[5]: variadic
От: rg45 СССР  
Дата: 25.09.23 14:28
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Я не раз подчеркивал, что регулярно применяю шаблоны по их прямому назначению. А то, что вместо вашей любимой SFINAE-магии мне часто удобнее применить макрос, который и проще, и понятнее, а часто еще и компактнее по коду — звиняйте, уж как есть.


Да-да, я в курсе, ты тут уже демонстрировал свое прямое назначение
Автор: Евгений Музыченко
Дата: 21.01.23
. Вот точно — мартышка и смартфон.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.09.2023 14:30 rg45 . Предыдущая версия .
Re[3]: наборы
От: Sm0ke Россия ksi
Дата: 25.09.23 14:34
Оценка:
Здравствуйте, Евгений Музыченко

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

Вот к примеру есть некий класс, который что-то хранит.
Если все действия, сваязяанные с его обработкой, запихать как методы в него
то он начинает разрастаться и "мозолить взгляд"

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

В итоге я написал вот такой простенький пример — один из вариантов — как это можно осуществить.
link: https://godbolt.org/z/q3x7TcfE5
#include <type_traits>
#include <iostream>

struct t_file;
struct t_console;
struct restrict;

template <typename Type>
struct io_actions
{
  using pointer = Type *;

  // data
  pointer self;

  // methods
  void read(restrict & p);
  void write(restrict & p);

  // hint
  io_actions * operator -> () { return this; }
};

struct restrict
{
  friend void io_actions<t_console>::write(restrict &);
  friend void io_actions<t_console>::read(restrict &);
  friend void io_actions<t_file>::write(restrict &);
  friend void io_actions<t_file>::read(restrict &);
private:
  int value{55};
};

struct t_console
{
  using trait = io_actions<t_console>;

  // data
  std::istream * in{& std::cin};
  std::ostream * out{& std::cout};

  trait operator -> () { return {this}; }
};

template <> void t_console::trait::read(restrict & p) { (*self->in) >> p.value; }
template <> void t_console::trait::write(restrict & p) { (*self->out) << p.value; }

int main()
{
  restrict v;
  t_console c;
  c->write(v);
  return 0;
}


Что тут происходит?
В траите io_actions только два метода read() и write(), которые работают с приватными данными из некого класса restrict

Понятно, что в дальнейшем можно определить и дополнительные отдельные траиты (наборы действий), скажем преобразования, проверка, да что угодно
, и оформить их как отдельный nest.

Почему я оформил trait как шаблонный?
Просто в данном случае конкретый обработчик может быть разным (консоль, файл, сеть, ещё куда)
И тут сами конкретные обработчики тоже not_over_bloated тучей кучей методов) а просто что-то хранят

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

Кстати, в примере выше нет definition для класса t_file
Вроде не сложно его сделать по анологии, если он вообще нужен
А действия тогда будут заданы как-то так:
template <> void t_file::trait::read(restrict & p) { /* ... */ }
template <> void t_file::trait::write(restrict & p) { /* ... */ }


p/s
Оператор стрелка у t_console создаёт временный объект-wrapper, это вообще-то под вопросом — как лучше можно оформить)

upd
По поводу iostream: я просто старался чтобы пример был понятным
Отредактировано 25.09.2023 14:40 Sm0ke . Предыдущая версия . Еще …
Отредактировано 25.09.2023 14:38 Sm0ke . Предыдущая версия .
Отредактировано 25.09.2023 14:37 Sm0ke . Предыдущая версия .
Отредактировано 25.09.2023 14:37 Sm0ke . Предыдущая версия .
Re[9]: Почему нельзя предварительно объявить дружественную ф
От: so5team https://stiffstream.com
Дата: 25.09.23 15:04
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Если ваш код не соответствует стандарту, то он запросто может перестать работать при обновлении компилятора.


ЕМ>Теоретически — может. А практически — ни разу не переставал. Он даже компилироваться ни разу не переставал — только новые предупреждения появлялись при /Wall.


Так это потому, что вы на компиляторах от одного производителя сидите.

ЕМ>Вот только практика показывает, что код, полностью соответствующий определенному стандарту, запросто может перестать компилироваться и/или работать при обновлении компилятора, ориентированного на более новые стандарты, и не поддерживающего старых (по крайней мере, по умолчанию). С этим что будем делать?


Если старый код не компилируется в рамках нового стандарта, то это вполне ожидаемо.
Выхода два:

— либо вы адаптируете код к новому стандарту;
— либо вы явно задаете стандарт ключиками компилятора. Ведь даже MS VC++ научили понимать /std.

ЕМ>Вообще, требование полного соответствия любого кода стандарту — это, грубо говоря, как требование надежной работы изделия в пределах хотя бы всей планеты — и на экваторе, и на полюсах, и в стратосфере, и под водой.


Бла-бла-бла.

ЕМ>Это не доблесть и не бравада. Это вполне разумный инженерный подход, который еще не так давно преобладал и в C, и в C++, а сейчас продолжает преобладать в большинстве других языков, для которых нет единых стандартов. А вот в C++ из стандарта сделали фетиш.


В мире не так-то много языков, у которых: а) есть международный стандарт и b) есть независимые его реализации от разных производителей.

Повторюсь, вам не приходилось переносить даже нормально написанный код между разными C++ компиляторами, поэтому вам кажется, что требование следовать стандарту C++ -- это фетиш. А вот тем, кому доводилось, понимают, что следование стандарту -- это хоть какая-то гарантия, что код хотя бы соберется на другом компиляторе.
Re[3]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 25.09.23 15:20
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Если нет менее кривого решения, я лучше объявлю дружественным весь класс, хотя пытаюсь этого избежать.


Какие-то странные поиски того, чего нет, когда можно решить "в лоб":
class A;
class B;

class A {
  friend void modify_A(A &, B &);
  ...

  void f(B & consumer);
};

class B {
  friend void modify_A(A &, B &);

public:
  ...
  void consume(A & a) {
    modify_A(a, *this);
  }
};

void A::f(B & consumer) {
  consumer.consume(*this);
}

void modify_A(A & a, B & b) {
  // Тут есть доступ и к потрохам A, и к потрохам B.
}
Re[10]: Почему нельзя предварительно объявить дружественную ф
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.09.23 17:00
Оценка:
Здравствуйте, so5team, Вы писали:

S>Так это потому, что вы на компиляторах от одного производителя сидите.


Что толку сидеть на разных, когда нужен результат в виде работающего двоичного кода, а не "ультрасовместимый" исходник?

S>В мире не так-то много языков, у которых: а) есть международный стандарт и b) есть независимые его реализации от разных производителей.


S>вам не приходилось переносить даже нормально написанный код между разными C++ компиляторами


Таки приходилось. И ненормально написанный тоже приходилось. И то, что было написано с прибором, положенным на стандарт, но где было видно, что именно "хотел сказать" программист, порой было проще переносить, чем то, что формально было написано правильно, но где ради совместимости и переносимости были нагорожены невнятные многоэтажные конструкции.

S>поэтому вам кажется, что требование следовать стандарту C++ -- это фетиш. А вот тем, кому доводилось, понимают, что следование стандарту -- это хоть какая-то гарантия, что код хотя бы соберется на другом компиляторе.


Там, где или первичен исходник (open source и подобное), или не могут жить без регулярных обновлений компиляторов "просто потому, что выпустили новый", необходимо следовать стандарту. Там, где первичен бинарник, а компилятор меняют не раньше, чем упрутся в нерешаемую имеющимся компилятором проблему, следование стандарту не столь важно, сколь получение предсказуемого кода.
Re[4]: Почему нельзя предварительно объявить дружественную функ
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.09.23 17:07
Оценка: +1
Здравствуйте, so5team, Вы писали:

S>Какие-то странные поиски того, чего нет, когда можно решить "в лоб":


Это ж тоже кривой костыль. Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B? "В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав.
Re[4]: Почему нельзя предварительно объявить дружественную функ
От: Sm0ke Россия ksi
Дата: 25.09.23 18:02
Оценка:
Здравствуйте, so5team, Вы писали:

S>Какие-то странные поиски того, чего нет, когда можно решить "в лоб":

S>
S>class A;
S>class B;

S>class A {
S>  friend void modify_A(A &, B &);
S>  ...

S>  void f(B & consumer);
S>};

S>class B {
S>  friend void modify_A(A &, B &);

S>public:
S>  ...
S>  void consume(A & a) {
S>    modify_A(a, *this);
S>  }
S>};

S>void A::f(B & consumer) {
S>  consumer.consume(*this);
S>}

S>void modify_A(A & a, B & b) {
S>  // Тут есть доступ и к потрохам A, и к потрохам B.
S>}
S>


Это обходные пути. Что, для каждого метода делать обёртку? А если их много — всё это ручками писать?

  cut
А может даже кодогенерировать? Если простые штуки в языке решаются через кодогенерацию, то стоит задуматься
Re[11]: Почему нельзя предварительно объявить дружественную ф
От: so5team https://stiffstream.com
Дата: 25.09.23 19:10
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Так это потому, что вы на компиляторах от одного производителя сидите.


ЕМ>Что толку сидеть на разных, когда нужен результат в виде работающего двоичного кода, а не "ультрасовместимый" исходник?


Тем, что в мире есть более одной платформы. Как программной, так и аппаратной.

S>>В мире не так-то много языков, у которых: а) есть международный стандарт и b) есть независимые его реализации от разных производителей.


S>>вам не приходилось переносить даже нормально написанный код между разными C++ компиляторами


ЕМ>Таки приходилось.


Судя по тому, что вы пишете, перенос был с VC++ 4.2 на VC++ 6.0.
Re[5]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 25.09.23 19:16
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B?


Тем, что тогда ее сможет вызвать кто угодно, а не только класс B. Ваш К.О.

ЕМ>"В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав.


Я так понял, что решается следующая задача:

— нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода);
— сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).

Если вам насрать на эту задачу и вы можете просто сделать класс B другом для класса A, то зачем весь этот кипешь?
Re[5]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 25.09.23 19:17
Оценка: +3
Здравствуйте, Sm0ke, Вы писали:

S>А если их много — всё это ручками писать?


Если у класса A слишком много друзей, то с классом A явно что-то не так.
Re[12]: Почему нельзя предварительно объявить дружественную ф
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.09.23 20:00
Оценка:
Здравствуйте, so5team, Вы писали:

S>в мире есть более одной платформы. Как программной, так и аппаратной.


Какова доля "истинно кросс-платформенного" кода на C++ во всем объеме кода на C++? А если вычесть формально существующий, но не используемый сколько-нибудь активно?

Чем дальше задача уходит от конкретной платформы, тем меньше остается оснований делать ее на C++.
Re[6]: Почему нельзя предварительно объявить дружественную функ
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.09.23 20:05
Оценка: :)
Здравствуйте, so5team, Вы писали:

ЕМ>>Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B?


S>Тем, что тогда ее сможет вызвать кто угодно, а не только класс B. Ваш К.О.


Скажите, К.О., а кто из перечисленных не сможет вызвать функцию modify_A?

S>- нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода);

S>- сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).

Верно.

S>Если вам насрать на эту задачу и вы можете просто сделать класс B другом для класса A, то зачем весь этот кипешь?


Вопрос, напоминаю, был не в том, как это сделать (способы решения есть разные, и все они в чем-то кривые), а в том, почему язык не допускает указания друзей-членов наперед, хотя принципиальных препятствий этому нет.
Re[7]: Почему нельзя предварительно объявить дружественную ф
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 25.09.23 20:15
Оценка: :)
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>Это еще большой вопрос, у кого мир более выдуманный. Я-то языком пользуюсь сугубо прагматично, для получения кода, надежно работающего в пределах заданных допущений, и не претендующего ни на полное соответствие Стандарту, ни на "каноничность".


Как ты изящно говнокод описал


ЕМ>На уровне "для работы" я его понимаю гораздо лучше среднего заурядного плюсовика, который тупо кодит алгоритмы по заданию.


Тупо кодит алгоритмы по заданию — это джун на испытательном сроке. Да и то, язык таки надо знать. И уж никак не средний заурядный плюсовик
Маньяк Робокряк колесит по городу
Re[9]: Почему нельзя предварительно объявить дружественную ф
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 25.09.23 20:17
Оценка: :)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Это не доблесть и не бравада. Это вполне разумный инженерный подход, который еще не так давно преобладал и в C, и в C++, а сейчас продолжает преобладать в большинстве других языков, для которых нет единых стандартов. А вот в C++ из стандарта сделали фетиш.


Хм. "Не делайте фетиш из стандарта". Надо записать
Маньяк Робокряк колесит по городу
Re[5]: variadic
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 25.09.23 20:20
Оценка: :)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Я не раз подчеркивал, что регулярно применяю шаблоны по их прямому назначению. А то, что вместо вашей любимой SFINAE-магии мне часто удобнее применить макрос, который и проще, и понятнее, а часто еще и компактнее по коду — звиняйте, уж как есть.


SFINAE-магия давно устарела
Маньяк Робокряк колесит по городу
Re[7]: Почему нельзя предварительно объявить дружественную функ
От: Sm0ke Россия ksi
Дата: 25.09.23 21:23
Оценка:
Здравствуйте, Евгений Музыченко, как думаете, когда-нибудь требование для forward declaration в языке си++ станут необязательными?
т.е. если некие имена видны _вконце_ единици трансляции, то все эти имена и будут видны из любой точки этой же единици трансляции.

А может быть уже есть я.п. в которых это реализовано?
Re[6]: read_only ячейка
От: Sm0ke Россия ksi
Дата: 25.09.23 21:38
Оценка:
Здравствуйте, so5team, Вы писали:

S>Если у класса A слишком много друзей, то с классом A явно что-то не так.


Надо ли перечислять друзей, Когда всё public: ?

--

Серьёзно: Если бы было ...
public read_only protected full_access:
... то число геттеров могло бы поубавиться
Отредактировано 25.09.2023 21:42 Sm0ke . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.