Re[2]: Как записать такое в современном C++?
От: Alekzander Россия  
Дата: 20.06.23 06:23
Оценка:
Здравствуйте, BSOD, Вы писали:

A>>Как это записать в современном C++, чтобы не было performance penalty? Без конструирования контейнера и т.п. Нормальных макросов же (как в Немерле), насколько я понимаю, не завезли?


BSO>
BSO>switch(errno)
BSO>    case EAGAIN:
BSO>    case EWOULDBLOCK:
BSO>    case EINTR:
BSO>    case ENOSPC:
BSO>    case ENOBUFS:
BSO>    case ENOMEM:
BSO>    {...}
BSO>


Выше написали, что при дублировании будет ошибка компиляции. А от себя добавлю, что ! выражать через default это верный способ сделать больше ошибок, а не меньше.
Re[5]: Как записать такое в современном C++?
От: Maniacal Россия  
Дата: 20.06.23 08:05
Оценка: +1
Здравствуйте, Alekzander, Вы писали:

A>Чего только нет в std... Ничего нет!


Похоже на отсылку к Жванецкому

У нас чего только может не быть. У нас всего может не быть. У нас чего только не захочешь, того может и не быть.

— Михаил Жванецкий
Re: Как записать такое в современном C++?
От: Dair Россия  
Дата: 20.06.23 08:39
Оценка:
Здравствуйте, Alekzander, Вы писали:

A> if (!(errno == EAGAIN || EWOULDBLOCK ||

A> errno == EINTR || errno == ENOSPC ||
A> errno == ENOBUFS || errno == ENOMEM)) {

Коллеги выше красиво написали, но почему-то упустили тот факт, что EWOULDBLOCK не находится в списке значений, которые не должен принимать errno.
Re[2]: Как записать такое в современном C++?
От: Sm0ke Россия ksi
Дата: 30.06.23 19:13
Оценка: 2 (1)
Здравствуйте, Dair, Вы писали:

D>Здравствуйте, Alekzander, Вы писали:


A>> if (!(errno == EAGAIN || EWOULDBLOCK ||

A>> errno == EINTR || errno == ENOSPC ||
A>> errno == ENOBUFS || errno == ENOMEM)) {

D>Коллеги выше красиво написали, но почему-то упустили тот факт, что EWOULDBLOCK не находится в списке значений, которые не должен принимать errno.


Этот фрагмент, как упоминается в исходной статье от студии PVS, содержит ошибку.

В исправленной версии там именно сравнение с errno.
Re[2]: Как записать такое в современном C++?
От: Sm0ke Россия ksi
Дата: 30.06.23 19:18
Оценка:
Здравствуйте, vopl, Вы писали:

V>например


V>
V>#include <errno.h>

V>template <auto... set>
V>bool isin(auto val)
V>{
V>    return (false || ... || (set == val));
V>}

V>int main() 
V>{
V>    // 
V>    if(isin<EAGAIN,
V>            EWOULDBLOCK,
V>            EINTR,
V>            ENOSPC,
V>            ENOBUFS,
V>            ENOMEM>(errno))
V>    {
V>        return 0;
V>    }

V>    return 1;
V>}
V>


Вот бы уменьшить число сравнений с помощью бинарного поиска в упорядоченном ряде значений.
Взять какой-нибудь constexpr set и вызвать метод contains().

Есть например https://github.com/serge-sans-paille/frozen , но я его не пробовал.
Отредактировано 30.06.2023 19:19 Sm0ke . Предыдущая версия .
Re: Как записать такое в современном C++?
От: B0FEE664  
Дата: 03.07.23 13:30
Оценка: 12 (2) +1
Здравствуйте, Alekzander, Вы писали:

A>Как это записать в современном C++, чтобы не было performance penalty?


Для такого случая у меня есть специальный класс:
template<class T>
class The
{
    public:
        constexpr explicit The(const T& x) noexcept
          : _x(x)
        {
        }

        template <class... TArgs>
        bool one_of(TArgs&&... args) const
        {
            return ((_x == args) || ...);
        }

        template <auto... VArgs>
        bool one_of() const
        {
            return ((_x == VArgs) || ...);
        }

    public:
        const T& _x;
};


На мой взгляд такой код легче читать, чем вариант с функцией
Автор: vopl
Дата: 17.06.23
:
int main() 
{
    // 
    if ( The(errno).one_of<
                           EAGAIN,
                           EWOULDBLOCK,
                           EINTR,
                           ENOSPC,
                           ENOBUFS,
                           ENOMEM
                         >()
       )
    {
        return 0;
    }

    return 1;
}
И каждый день — без права на ошибку...
Re[2]: Как записать такое в современном C++?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 03.07.23 14:22
Оценка:
Здравствуйте, BSOD, Вы писали:

BSO>switch(errno)

BSO> case EAGAIN:
BSO> case EWOULDBLOCK:
BSO> case EINTR:
BSO> case ENOSPC:
BSO> case ENOBUFS:
BSO> case ENOMEM:
BSO> {...}

Тут есть одна проблемка: на большинстве систем коды EAGAIN и EWOULDBLOCK сейчас совпадают (такое вот легаси), но есть специфические, где они различны. При совпадении switch выдаёт ошибку.
Можно проверять препроцессором, но это ещё больше левых слов.
А в варианте с == проблемы не возникает
The God is real, unless declared integer.
Re[3]: Как записать такое в современном C++?
От: kov_serg Россия  
Дата: 03.07.23 15:46
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Вот бы уменьшить число сравнений с помощью бинарного поиска в упорядоченном ряде значений.

S>Взять какой-нибудь constexpr set и вызвать метод contains().
C++ и так это способен оптимизировать до битовых полей, что бы сравнивать группами.
Re: Как записать такое в современном C++?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 27.07.24 20:16
Оценка: -1
Здравствуйте, Alekzander, Вы писали:

A>Код надо писать так, чтобы его нельзя было записать неправильно


Такой подход неизбежно вырождается в известное "создайте систему, которой сможет пользоваться дурак, и только дурак захочет ею пользоваться". Невозможно (и не нужно) загодя предусмотреть все мыслимые косяки, которые могут возникнуть в применении какого-либо инструмента. А вот возможность доработки инструмента предусматривать как раз полезно — ту же болгарку можно использовать и с защитным кожухом, и без него, или, наоборот, зажать в какой-нибудь привод и накрыть всю эту конструкцию общим кожухом.

В данном случае самое правильное — с одной стороны, иметь в языке средства для удобной и эффективной записи подобных конструкций, а с другой — иметь в его компиляторе предупреждения на любые подозрительные конструкции.
Re[2]: Как записать такое в современном C++?
От: Alekzander Россия  
Дата: 27.07.24 20:27
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

A>>Код надо писать так, чтобы его нельзя было записать неправильно


ЕМ>Такой подход неизбежно вырождается в известное "создайте систему, которой сможет пользоваться дурак, и только дурак захочет ею пользоваться". Невозможно (и не нужно) загодя предусмотреть все мыслимые косяки, которые могут возникнуть в применении какого-либо инструмента. А вот возможность доработки инструмента предусматривать как раз полезно — ту же болгарку можно использовать и с защитным кожухом, и без него, или, наоборот, зажать в какой-нибудь привод и накрыть всю эту конструкцию общим кожухом.


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


Я понял. На самом деле я дурак, и мне это не надо. Классика русскоязычных форумов по программированию ))
Re[3]: Как записать такое в современном C++?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 27.07.24 21:49
Оценка: :))
Здравствуйте, Alekzander, Вы писали:

A>На самом деле я дурак, и мне это не надо. Классика русскоязычных форумов по программированию ))


Возможно, Вам "это" и надо, но, получив частное решение, Вы скоро столкнетесь с похожим случаем, "вот точно таким же, только другим", и для него снова потребуется частное решение. На какой итерации уже надоест, и захочется более общего?
Re[4]: Как записать такое в современном C++?
От: B0FEE664  
Дата: 29.07.24 10:15
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Возможно, Вам "это" и надо, но, получив частное решение, Вы скоро столкнетесь с похожим случаем, "вот точно таким же, только другим", и для него снова потребуется частное решение. На какой итерации уже надоест, и захочется более общего?


В чём "частность" такого решения
Автор: B0FEE664
Дата: 03.07.23
?
И каждый день — без права на ошибку...
Re[4]: Как записать такое в современном C++?
От: Alekzander Россия  
Дата: 29.07.24 12:33
Оценка: :)
Здравствуйте, Евгений Музыченко, Вы писали:

A>>На самом деле я дурак, и мне это не надо. Классика русскоязычных форумов по программированию ))


ЕМ>Возможно, Вам "это" и надо, но, получив частное решение, Вы скоро столкнетесь с похожим случаем, "вот точно таким же, только другим", и для него снова потребуется частное решение. На какой итерации уже надоест, и захочется более общего?


Я внезапно понял, что ты просто не умеешь программировать. Зато умничаешь как Александреску.

Любой, буквально любой джун, если он хотя бы год попрограммировал, увидит тут следующее. У нас есть одна и та же операция над каждым элементом множества. Но мы записываем её не один раз, а копируем код операции для каждого элемента. Это называется "нарушение DRY" в виде копипасты. К чему приводит копипаста очень хорошо видно из статьи, на которую я сослался. Но есть и другие соображения. Например, если у нас сравнение нетривиальное, и цена его после рефакторинга выросла, в is_in_set простое развёртывание можно заменить кешированием профиля. Но это обсуждение, боюсь, требует другого уровня квалификации. Такого, когда человек сам способен разглядеть копипасту, а не ждёт, когда его натычут в неё носом.
Re[5]: Как записать такое в современном C++?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.07.24 13:25
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>В чём "частность" такого решения
Автор: B0FEE664
Дата: 03.07.23
?


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

Это не говоря уже о том, что сделать опечатку в вызове такого хитровыгнутого шаблона тоже достаточно легко, и по кучке сообщений об ошибках, которую компилятор насыпет в ответ, тоже далеко не сразу поймешь, что именно не так.
Re[6]: Как записать такое в современном C++?
От: B0FEE664  
Дата: 29.07.24 18:30
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>В чём "частность" такого решения
Автор: B0FEE664
Дата: 03.07.23
?

ЕМ>В том, что устраняется лишь один вид возможной опечатки, и реализуется так же лишь один вид сравнений (простая однородная последовательность). Во менее однородных сравнениях (например, где нужно дополнительно проверить другие условия) все останется по-прежнему.

Видите ли, это у автора темы был вопрос про опечатку, я же писал этот класс из совсем других соображений, главным образом для компактности и выразительности кода. Обычным использованием этого класса у меня является такой код:
assert((The(fileType).one_of<0, 1, 2, 3, 4>()));
Мне легче его читать, чем пять сравнений соединённых через ||

Реже встречаются строчки вида
    if ( The(m_phase).one_of<EPhase::eIdle, EPhase::ePauseBetweenSeries>() )


Редко с дополнительным условием:
    return ! (std::isalnum(ch) || The(ch).one_of<'.', '-'>());


Для меня этот код не частный, а наоборот, слишком общий и некоторые его возможности вообще не используются. Например, вот такое его применение я не нахожу оправданным
    int a = 3;
    int b = 4;
    int c = 5;
    int d = 5;

    std::cout << The(true).one_of(a == b, b == c, c == a) << std::endl;
    std::cout << The(true).one_of(a == b, b == c, c == d) << std::endl;


Поэтому иногда, чтобы избежать общности, я заменяю его более частными случаями прописывая метод класса вида:
template<Mode... modeArgs>
inline bool MyClass::IsMode() const noexcept
{
    return ((m_mode == modeArgs) || ...);
}

  if ( IsMode<Mode::A>() )
    ...
  if ( IsMode<Mode::A, Mode::B>() )
    ...


Короче, я хочу сказать, что нахожу такой код чересчур общим, а никак не частным.


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

Лучше получить ошибку компиляции, чем ошибку выполнения.
И каждый день — без права на ошибку...
Re[4]: Как записать такое в современном C++?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.07.24 18:37
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>C++ и так это способен оптимизировать до битовых полей, что бы сравнивать группами.


Именно C++? Или таки один-два конкретных компилятора?
Re[7]: Как записать такое в современном C++?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.07.24 18:59
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>assert((The(fileType).one_of<0, 1, 2, 3, 4>()));

BFE>Мне легче его читать, чем пять сравнений соединённых через ||

И Вас не смущает, что из такой формулировки, как правило, не следует, какой смысл имеет данное подмножество и, по-хорошему, нужен дополнительный комментарий?

BFE>нахожу такой код чересчур общим, а никак не частным.


Я тоже очень люблю всяческие избыточные проверки и assert'ы, но не припомню, чтоб мне приходилось в товарных количествах проверять переменные на равенство не связанным между собой значениям. Разовые проверки обычно укладываются максимум в два-три варианта или проверку вхождения в диапазон. Если же набор вариантов более сложный, как в примере у ТС, и встречается более одного раза, то гораздо правильнее сделать осмысленный предикат "значение удовлетворяет условию".

А если делать средства, как у Вас, просто для компактной и "более надежной" записи систематических выражений, можно докатиться и до замены "a + b + c" на "sum (a, b, c)".

В принципе, я вовсе не против подобных средств группировки. Но засада-то в том, что это сильно избыточно (на каждый вызов создается отдельный класс, который нигде больше не нужен), и весьма уродливо (реализация пакетов параметров шаблона, как очередное сугубо частное решение, худо-бедно годится для подобных последовательностей, а последовательности более другого вида не поймет, и их по-прежнему придется выписывать руками).
Re: Как записать такое в современном C++?
От: Pzz Россия https://github.com/alexpevzner
Дата: 30.07.24 00:01
Оценка: 15 (1)
Здравствуйте, Alekzander, Вы писали:

A>Тут недавно была статья от создателей PVS, как надо и не надо писать код. В ней автор приводил следующий пример с ошибкой:


A>
A>void adns__querysend_tcp(adns_query qu, struct timeval now) {
A>  ...
A>  if (!(errno == EAGAIN || EWOULDBLOCK || 
A>        errno == EINTR || errno == ENOSPC ||
A>        errno == ENOBUFS || errno == ENOMEM)) {
A>  ...
A>}
A>


Я б вот так написал:

    if (errno == EAGAIN) {
        errno = EWOULDBLOCK;
    }

    switch (errno) {
    case EWOULDBLOCK:
    case EINTR:
    case ENOSPC:
    case ENOBUFS:
    case ENOMEM:
        . . . .
    }


С EWOULDBLOCK есть та проблема, что на некоторых системах это alias к EAGAIN, а на некоторых — нет. Поэтому с ним приходится что-то некрасивое делать.
Re[2]: Как записать такое в современном C++?
От: reversecode google
Дата: 30.07.24 00:04
Оценка: 15 (1) -2
в православном C++
там есть std::error_code который уже имеет правильное для этого имя-значение
которое правильно задефайнено для разных ОС
Re[3]: Как записать такое в современном C++?
От: Pzz Россия https://github.com/alexpevzner
Дата: 30.07.24 00:06
Оценка: +1
Здравствуйте, Alekzander, Вы писали:

A>Предикат через switch-case... такое. Тем более, в данном случае по невнимательности ошибок ещё больше настряпаешь, чем с простым if'ом.


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