Opened 4 years ago

Closed 4 years ago

#985 closed ожидается проверка (задача сдана)

WW #15

Reported by: lebedev.egor Owned by: Дмитрий Свиридкин
Component: WW_linq Version: 3.0
Keywords: Cc:

Description

Шаблоны - (слишком) веселая штука, оказывается...
Без копипасты сделать было как-то больно, поэтому там что-то страшное с CRTP, но зато два раза повторяется только функция вида return (bool)parent_, что, кажется, довольно неплохо...

Attachments (2)

32_select.vg (3.1 KB) - added by Дмитрий Свиридкин 4 years ago.
23_until.vg (4.9 KB) - added by Дмитрий Свиридкин 4 years ago.

Download all attachments as: .zip

Change History (14)

comment:1 Changed 4 years ago by Дмитрий Свиридкин

Type: ожидается проверкаожидаются исправления
  • У вас UB, если делать drop большего числа элементов, чем есть.
  • drop не ленивый
  • until упадет на пустой последовательности

*

template<typename T, typename Derrived>
auto basic_enumerator<T, Derrived>::until_eq(const T& val) {
    Derrived* self = static_cast<Derrived*>(this);
    auto lambda = [val](const T& element){ return element == val; };
    return until_enumerator<T, Derrived, decltype(lambda)>(*self, lambda);
}

Можно использовать уже определенный until и не мучаться. С where_neq тоже.
->

   return this->until([val](const T& element) { return element == val; });

*

void basic_enumerator<T, Derrived>::copy_to(Iter it) {
    while (*this) {
        it = **this;
        ++*this;
    }
}

а выходной итератор кто двигать будет?
to_vector можно реализовать через copy_to и не дублировать код.

  • (bool)middle_stage_enumerator<T, ParentType>::parent_ давайте делать красивый static_cast, а не этот пережиток C.

У вас, кстати, этот оператор не помечен explicit, так что cast не обязателен.

  • Чтобы постоянно не писать все длинное название базового класса, можно сделать внутри класса

using Base = <long-templated-base-class-name>

  • until и where тоже не совсем ленивые.
  • возвращать элементы по ссылкам тут не очень хорошая идея. Потому что ссылки будут инвалидироваться при сдвиге итератора. Чтобы правильно реализовать передачу по ссылке или по копии, в зависимости от функтора, нужно отказаться от виртуальных функций.
  • из-за предыдущего у может быть UB при комбинации select и любого итератора, хранящего ссылку/указатель
  • постарайтесь не копировать передаваемые функторы.
  • можно проверить, что переданный функтор имеет корректную сигнатуру с помощью std::is_invocable

comment:2 Changed 4 years ago by Дмитрий Свиридкин

Owner: changed from Дмитрий Свиридкин to lebedev.egor

comment:3 Changed 4 years ago by lebedev.egor

Owner: changed from lebedev.egor to Дмитрий Свиридкин
Type: ожидаются исправленияожидается проверка
Version: 1.02.0
  • Теперь не должно падать на пустой, и UB быть не должно.
  • Ленивость drop'a (и других) не исправлял, ибо немного изменилось условие
  • Убрал виртуальные методы вообще, но теперь методы наследников просто перекрывают методы базового класса, не уверен, что это плохо, но clang-tidy такому особо не рад...
  • Пофиксил стиль в каких-то местах (везде, где увидел/было написано)
  • Передаваемые функторы не копирую, но мне не очень нравится, как я их не копирую, кажется, это немного противоречит здравому смыслу, но не условию (чтобы не противоречить здравому смыслу надо было бы еще 1 конструктор у where, until, select делать, но условию явно говорит, что такое не надо)
  • Реализовал copy_to через to_vector
  • Корректная сигнатура функтора теперь проверяется
  • (не уверен, что static_cast<bool>(parent) красивее, чем (bool)parent, но допустим)
Last edited 4 years ago by lebedev.egor (previous) (diff)

comment:4 Changed 4 years ago by Дмитрий Свиридкин

  • Если нет виртуальности, то перекрываемые методы из базового класса надо убрать. При использовании CRTP они там и не нужны.
  • select сегфолтит, в until UB. Смотрите приложенные логи

Changed 4 years ago by Дмитрий Свиридкин

Attachment: 32_select.vg added

Changed 4 years ago by Дмитрий Свиридкин

Attachment: 23_until.vg added

comment:5 in reply to:  4 ; Changed 4 years ago by lebedev.egor

  • Если нет виртуальности, то перекрываемые методы из базового класса надо убрать. При использовании CRTP они там и не нужны.

Тогда это будет тонна копирования кода, чего хотелось избежать

comment:6 in reply to:  5 Changed 4 years ago by Дмитрий Свиридкин

Replying to lebedev.egor:

  • Если нет виртуальности, то перекрываемые методы из базового класса надо убрать. При использовании CRTP они там и не нужны.

Тогда это будет тонна копирования кода, чего хотелось избежать

Не будет. Поместите select и прочие методы в отдельный базовый класс и только в нем и нужен CRTP.
Операторы вы перекрываете в любом случае.
Сейчас у вас CRTP используется там, где не надо. От чего ни читать, ни поддерживать это невозможно.

comment:7 Changed 4 years ago by Дмитрий Свиридкин

https://github.com/Nekrolm/hse_cpp_examples/blob/master/templates/select.cpp

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

comment:8 Changed 4 years ago by Дмитрий Свиридкин

Type: ожидается проверкаожидаются исправления

comment:9 Changed 4 years ago by Дмитрий Свиридкин

Owner: changed from Дмитрий Свиридкин to lebedev.egor

comment:10 Changed 4 years ago by Дмитрий Свиридкин

3.5 + 2.5

comment:11 Changed 4 years ago by lebedev.egor

Owner: changed from lebedev.egor to Дмитрий Свиридкин
Type: ожидаются исправленияожидается проверка
Version: 2.03.0

сегфолт и UB ушли, теперь, кажется, все работает корректно. На остальное времени не хватило :(

comment:12 Changed 4 years ago by Дмитрий Свиридкин

Resolution: задача сдана
Status: assignedclosed

все-таки лучше реализовывать to_vector через copy_to, а не наоборот. Чтобы не создавать лишний промежуточный вектор.


6 + 2.8

Note: See TracTickets for help on using tickets.