Здравствуйте, Sm0ke, Вы писали:
S>ради эксперимента S>Попробовал этот трюк провернуть с вариадиками, но что-то пошло не так: https://godbolt.org/z/9rdGfzn76
Перед кем ты бисер мечешь? Его от шаблонов корежит, как вампира от чеснока, он макросы использует, только чтоб к шаблонам не прикасаться. А ты ему вариадики.
--
Re[8]: Почему нельзя предварительно объявить дружественную ф
Здравствуйте, so5team, Вы писали:
S>Если ваш код не соответствует стандарту, то он запросто может перестать работать при обновлении компилятора.
Теоретически — может. А практически — ни разу не переставал. Он даже компилироваться ни разу не переставал — только новые предупреждения появлялись при /Wall.
Вот только практика показывает, что код, полностью соответствующий определенному стандарту, запросто может перестать компилироваться и/или работать при обновлении компилятора, ориентированного на более новые стандарты, и не поддерживающего старых (по крайней мере, по умолчанию). С этим что будем делать?
Вообще, требование полного соответствия любого кода стандарту — это, грубо говоря, как требование надежной работы изделия в пределах хотя бы всей планеты — и на экваторе, и на полюсах, и в стратосфере, и под водой. Для некоторых изделий это необходимо, но для подавляющего большинства вполне достаточно "разумных условий". Ежели у кого автомобиль, сделанный в Испании, плохо заводится в Якутии или на Аляске, он почему-то не спешит объявлять его "не соответствующими стандарту автомобиля".
S>Но доблести, увы, в этом нет. И у людей, которые набили шишек при переносе кода между vc++, gcc и clang (хотя бы этими тремя), подобная бравада одобрения не вызывает, мягко говоря.
Это не доблесть и не бравада. Это вполне разумный инженерный подход, который еще не так давно преобладал и в C, и в C++, а сейчас продолжает преобладать в большинстве других языков, для которых нет единых стандартов. А вот в C++ из стандарта сделали фетиш.
Здравствуйте, rg45, Вы писали:
R>Его от шаблонов корежит, как вампира от чеснока, он макросы использует, только чтоб к шаблонам не прикасаться.
Я не раз подчеркивал, что регулярно применяю шаблоны по их прямому назначению. А то, что вместо вашей любимой SFINAE-магии мне часто удобнее применить макрос, который и проще, и понятнее, а часто еще и компактнее по коду — звиняйте, уж как есть.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я не раз подчеркивал, что регулярно применяю шаблоны по их прямому назначению. А то, что вместо вашей любимой SFINAE-магии мне часто удобнее применить макрос, который и проще, и понятнее, а часто еще и компактнее по коду — звиняйте, уж как есть.
Это обсуждение привело меня к размышлениям над смежной темой.
А именно об отделдении структур для хранения данных от
набора действий над ними.
Вот к примеру есть некий класс, который что-то хранит.
Если все действия, сваязяанные с его обработкой, запихать как методы в него
то он начинает разрастаться и "мозолить взгляд"
Мне знакомо пожелание разработчика определить общие действия над разными данными
, и как-то их сгруппировать.
В итоге я написал вот такой простенький пример — один из вариантов — как это можно осуществить.
link: https://godbolt.org/z/q3x7TcfE5
Что тут происходит?
В траите io_actions только два метода read() и write(), которые работают с приватными данными из некого класса restrict
Понятно, что в дальнейшем можно определить и дополнительные отдельные траиты (наборы действий), скажем преобразования, проверка, да что угодно
, и оформить их как отдельный nest.
Почему я оформил trait как шаблонный?
Просто в данном случае конкретый обработчик может быть разным (консоль, файл, сеть, ещё куда)
И тут сами конкретные обработчики тоже not_over_bloated тучей кучей методов) а просто что-то хранят
Такая штука работает без интерфейса с виртуальными методами, которые хочется по возможности избежать.
Кстати, в примере выше нет definition для класса t_file
Вроде не сложно его сделать по анологии, если он вообще нужен
А действия тогда будут заданы как-то так:
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Если ваш код не соответствует стандарту, то он запросто может перестать работать при обновлении компилятора.
ЕМ>Теоретически — может. А практически — ни разу не переставал. Он даже компилироваться ни разу не переставал — только новые предупреждения появлялись при /Wall.
Так это потому, что вы на компиляторах от одного производителя сидите.
ЕМ>Вот только практика показывает, что код, полностью соответствующий определенному стандарту, запросто может перестать компилироваться и/или работать при обновлении компилятора, ориентированного на более новые стандарты, и не поддерживающего старых (по крайней мере, по умолчанию). С этим что будем делать?
Если старый код не компилируется в рамках нового стандарта, то это вполне ожидаемо.
Выхода два:
— либо вы адаптируете код к новому стандарту;
— либо вы явно задаете стандарт ключиками компилятора. Ведь даже MS VC++ научили понимать /std.
ЕМ>Вообще, требование полного соответствия любого кода стандарту — это, грубо говоря, как требование надежной работы изделия в пределах хотя бы всей планеты — и на экваторе, и на полюсах, и в стратосфере, и под водой.
Бла-бла-бла.
ЕМ>Это не доблесть и не бравада. Это вполне разумный инженерный подход, который еще не так давно преобладал и в C, и в C++, а сейчас продолжает преобладать в большинстве других языков, для которых нет единых стандартов. А вот в C++ из стандарта сделали фетиш.
В мире не так-то много языков, у которых: а) есть международный стандарт и b) есть независимые его реализации от разных производителей.
Повторюсь, вам не приходилось переносить даже нормально написанный код между разными C++ компиляторами, поэтому вам кажется, что требование следовать стандарту C++ -- это фетиш. А вот тем, кому доводилось, понимают, что следование стандарту -- это хоть какая-то гарантия, что код хотя бы соберется на другом компиляторе.
Re[3]: Почему нельзя предварительно объявить дружественную функ
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Если нет менее кривого решения, я лучше объявлю дружественным весь класс, хотя пытаюсь этого избежать.
Какие-то странные поиски того, чего нет, когда можно решить "в лоб":
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]: Почему нельзя предварительно объявить дружественную ф
Здравствуйте, so5team, Вы писали:
S>Так это потому, что вы на компиляторах от одного производителя сидите.
Что толку сидеть на разных, когда нужен результат в виде работающего двоичного кода, а не "ультрасовместимый" исходник?
S>В мире не так-то много языков, у которых: а) есть международный стандарт и b) есть независимые его реализации от разных производителей.
S>вам не приходилось переносить даже нормально написанный код между разными C++ компиляторами
Таки приходилось. И ненормально написанный тоже приходилось. И то, что было написано с прибором, положенным на стандарт, но где было видно, что именно "хотел сказать" программист, порой было проще переносить, чем то, что формально было написано правильно, но где ради совместимости и переносимости были нагорожены невнятные многоэтажные конструкции.
S>поэтому вам кажется, что требование следовать стандарту C++ -- это фетиш. А вот тем, кому доводилось, понимают, что следование стандарту -- это хоть какая-то гарантия, что код хотя бы соберется на другом компиляторе.
Там, где или первичен исходник (open source и подобное), или не могут жить без регулярных обновлений компиляторов "просто потому, что выпустили новый", необходимо следовать стандарту. Там, где первичен бинарник, а компилятор меняют не раньше, чем упрутся в нерешаемую имеющимся компилятором проблему, следование стандарту не столь важно, сколь получение предсказуемого кода.
Re[4]: Почему нельзя предварительно объявить дружественную функ
Здравствуйте, so5team, Вы писали:
S>Какие-то странные поиски того, чего нет, когда можно решить "в лоб":
Это ж тоже кривой костыль. Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B? "В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав.
Re[4]: Почему нельзя предварительно объявить дружественную функ
Здравствуйте, 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]: Почему нельзя предварительно объявить дружественную ф
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Так это потому, что вы на компиляторах от одного производителя сидите.
ЕМ>Что толку сидеть на разных, когда нужен результат в виде работающего двоичного кода, а не "ультрасовместимый" исходник?
Тем, что в мире есть более одной платформы. Как программной, так и аппаратной.
S>>В мире не так-то много языков, у которых: а) есть международный стандарт и b) есть независимые его реализации от разных производителей.
S>>вам не приходилось переносить даже нормально написанный код между разными C++ компиляторами
ЕМ>Таки приходилось.
Судя по тому, что вы пишете, перенос был с VC++ 4.2 на VC++ 6.0.
Re[5]: Почему нельзя предварительно объявить дружественную функ
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B?
Тем, что тогда ее сможет вызвать кто угодно, а не только класс B. Ваш К.О.
ЕМ>"В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав.
Я так понял, что решается следующая задача:
— нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода);
— сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).
Если вам насрать на эту задачу и вы можете просто сделать класс B другом для класса A, то зачем весь этот кипешь?
Re[5]: Почему нельзя предварительно объявить дружественную функ
Здравствуйте, so5team, Вы писали:
S>в мире есть более одной платформы. Как программной, так и аппаратной.
Какова доля "истинно кросс-платформенного" кода на C++ во всем объеме кода на C++? А если вычесть формально существующий, но не используемый сколько-нибудь активно?
Чем дальше задача уходит от конкретной платформы, тем меньше остается оснований делать ее на C++.
Re[6]: Почему нельзя предварительно объявить дружественную функ
Здравствуйте, so5team, Вы писали:
ЕМ>>Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B?
S>Тем, что тогда ее сможет вызвать кто угодно, а не только класс B. Ваш К.О.
Скажите, К.О., а кто из перечисленных не сможет вызвать функцию modify_A?
S>- нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода); S>- сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).
Верно.
S>Если вам насрать на эту задачу и вы можете просто сделать класс B другом для класса A, то зачем весь этот кипешь?
Вопрос, напоминаю, был не в том, как это сделать (способы решения есть разные, и все они в чем-то кривые), а в том, почему язык не допускает указания друзей-членов наперед, хотя принципиальных препятствий этому нет.
Re[7]: Почему нельзя предварительно объявить дружественную ф
ЕМ>Это еще большой вопрос, у кого мир более выдуманный. Я-то языком пользуюсь сугубо прагматично, для получения кода, надежно работающего в пределах заданных допущений, и не претендующего ни на полное соответствие Стандарту, ни на "каноничность".
Как ты изящно говнокод описал
ЕМ>На уровне "для работы" я его понимаю гораздо лучше среднего заурядного плюсовика, который тупо кодит алгоритмы по заданию.
Тупо кодит алгоритмы по заданию — это джун на испытательном сроке. Да и то, язык таки надо знать. И уж никак не средний заурядный плюсовик
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Это не доблесть и не бравада. Это вполне разумный инженерный подход, который еще не так давно преобладал и в C, и в C++, а сейчас продолжает преобладать в большинстве других языков, для которых нет единых стандартов. А вот в C++ из стандарта сделали фетиш.
Хм. "Не делайте фетиш из стандарта". Надо записать
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я не раз подчеркивал, что регулярно применяю шаблоны по их прямому назначению. А то, что вместо вашей любимой SFINAE-магии мне часто удобнее применить макрос, который и проще, и понятнее, а часто еще и компактнее по коду — звиняйте, уж как есть.
Здравствуйте, Евгений Музыченко, как думаете, когда-нибудь требование для forward declaration в языке си++ станут необязательными?
т.е. если некие имена видны _вконце_ единици трансляции, то все эти имена и будут видны из любой точки этой же единици трансляции.
А может быть уже есть я.п. в которых это реализовано?