Как стать автором
Обновить

Комментарии 19

auto read ( FileName file_name );
auto read ( Url url );

За такую кодяру нужно по рукам бить. Сиди потом, разбирайся, что такое FileName, а что такое Url.

НЛО прилетело и опубликовало эту надпись здесь

Подход strong typedef к простой декларации новых типов на основе существующих известен достаточно давно и имеет свою реализацию, например, в Boost.
Здесь показана возможность реализации такого подхода с помощью "умной" обертки на основе примера из доклада на коференции CppCon 2018.

И FileName и Url являются отдельными типами, а не синонимами. В этом весь смысл.

это очень известный паттер, который поддерживает множество авторитетных людей в языке, включая Страуструпа

например, есть масса единиц измерения: метры, килограммы, секунды и так далее. и он все могут представлены как float (или там double)

и такого рода подходы позволяют полностью отследить корректность этих единиц во всей программе, что спасает от большого количества разных ошибок

НЛО прилетело и опубликовало эту надпись здесь

Ага, а потом рыцарь ордена битья рук линейкой пишет что-нибудь вроде:

void set_duration(int first_delay, int loop_duration);

И сиди потом разбирайся, в каких единицах параметр. И через год исправляй ошибки за кем-то, кто неглядя решил, что там секунды.

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

НЛО прилетело и опубликовало эту надпись здесь

Вы жестокий человек, если считаете нормальным по какому-то такому мелочному вопросу бить людей по рукам ?

    for ( const auto & value : values )
        cout << *&value << endl;
В чём смысл *&?

P.S. Кодстайл ужасный, читать очень тяжело. Чтобы отличить операторы от ссылок (&, &&) и шаблонов (<, >), приходится вникать в семантику.

(я не автор поста) По-моему, смысл & - создать временный объект ValuePointer, с вызовом guard в конструкторе и unguard в деструкторе. Ну а * - собственно взять завёрнутое в этот временный ValuePointer значение, но! - с дополнительными приспоблениями, реализованными в guard / unguard (ну, потоковая безопасность, что-то такое). Польза!

Конечно, невнимательный прикладной программист может случайно забыть добавить *& -- и не получить пользы. Код будет как бы работать, но не совсем: что-то крэшнется, что-то полетит не туда. Ну а кто сказал, что профессия программиста - простая и лёгкая? Программист должен быть внимательным!

Т.е. итераторы враппера разыменовываются не в тип хранимых значений, а во враппер над значением? Враппер же непрозрачным становится, вся соль теряется, плюс не очевидно совсем.

Да и настолько неочевидное использование операторов это ужас какой-то. Это как на условный ++ повесить lock, а на -- unlock.

А намёки на потокобезопасность встречаются только в примерах с ThreadSafe::*, так что непонятно, зачем в примере с простейшим случаем вообще какие-то guard'ы.

Кодстайл ужасный, читать очень тяжело.

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

for ( const auto & value : values )
        cout << value << endl;

Как раз над этим сейчас и работаю).

Если вы продолжаете работать над проектом, обратите, пожалуйста, внимание на правильность английского в идентификаторах, названиях файлов - IsXyzExists плохо звучит. Уберите.Is или замените на Does, убрав s на конце (DoesXyzExist).

Не откладывая в долгий ящик, всё в проекте поправил. Спасибо за замечание, действительно глаз режет.

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

а) снабжать его максимально удобной и исчерпывающийся документацией на английском языке

б) полностью покрывать юнит тестами (которые, помимо всего прочего, выступают еще и хоть какими-то примерами использования библиотеки)

Если "потокобезопасность" это добавление на каждую операцию лока, то это не потокобезопасность
if(map.empty())
map.DO ANYTHING()

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

Да и вообще невозможно на С++ сделать "strong typedef" универсальный в шаблоне. Этим будет невозможно пользоваться.

Ну и сложность гит проекта поражает(не в хорошем смысле) + нужно указывать, что вы используете нестандартные возможности(баги) языка типа loopholes
https://gitlab.com/ssoft-scl/module/model-kit/-/blob/master/src/Meta/Counter.h

Если "потокобезопасность" это добавление на каждую операцию лока, то это не потокобезопасность

Средства библиотеки позволяют сделать операцию lock, как на каждую операцию отдельно, так и на любой блок кода, в зависимости от желаний разработчика. На постоянной основе сейчас можно сделать блокировку так

using Map = Wrapper< map, ThreadSafe::RecursiveMutex >;
Map map;

void foo ()
{
    // в месте, где нужен постоянный lock
    auto map_ptr = &map;
        // map_ptr - умный указатель, который выполнил lock
    if ( map_ptr->empty() )
        map_ptr->doAnything();
}
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории