Почему простой итератор не читается? - PullRequest
2 голосов
/ 02 апреля 2020

Этот код не компилируется с range-v3 0.10.0 (или с master). Он компилируется с range-v3 0.9.1.

#include "range/v3/all.hpp"

struct double_it {
  using value_type = double;
  double x;
  double& operator*() { return x; }
  const double& operator*() const { return x; }
};
static_assert(ranges::readable<double_it>);

Какая версия подходит? В master тип I равен readable, только если same_as<iter_reference_t<I const>, iter_reference_t<I>>. Я не понимаю, почему тип возвращаемого значения operator* должен совпадать с типом возврата operator* const.

Примечание: проблема отправлена ​​на github здесь .

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

Взгляните на P1878 , в котором есть все основания для этого позднего изменения дизайна. Итераторы представляют косвенные выражения. В C ++ const -ness незначительна, то есть не следует косвенным указаниям. Независимо от того, используете ли вы int* или int*const, вы получите тот же результат: int&. Верхний уровень const не имеет и не должен иметь значения. Итераторы делают как указатели. Они должны, потому что указатель является допустимой моделью концепции итератора.

Чтобы сделать это различие более явным, в C ++ 20 концепция readable называется indirectly_readable.

TL; DR: не делайте ссылочный тип вашего итератора зависимым от const -ности самого итератора.

1 голос
/ 02 апреля 2020

По-видимому, это как минимум несоответствие в range-v3 по сравнению с рабочим проектом TS Ranges.

Существует довольно скудное описание того, почему были добавлены эти предикаты same_as. к к концепции readable для итераторов в range-v3 выпуск 1449 .

Получить библиотеку диапазонов, компилируемую с msv c 19.24.28319 с / std : c ++ 17

...

- CPP_concept_fragment(readable_, (I),
+ CPP_concept_fragment(readable_,
+     requires (/*I const i*/) //
+     (
+         // { *i } -> same_as<iter_reference_t<I>>;
+         // { iter_move(i) } -> same_as<iter_rvalue_reference_t<I>>;
+         0
+     ) &&
+     same_as<iter_reference_t<I const>, iter_reference_t<I>> &&
+     same_as<iter_rvalue_reference_t<I const>, iter_rvalue_reference_t<I>> &&
      common_reference_with<iter_reference_t<I> &&, iter_value_t<I> &> &&
      common_reference_with<iter_reference_t<I> &&,
                            iter_rvalue_reference_t<I> &&> &&
      common_reference_with<iter_rvalue_reference_t<I> &&, iter_value_t<I> const &>
  );

Кажется, что предикаты same_as в реализации концепции предназначены для реализации требования:

// { *i } -> same_as<iter_reference_t<I>>;
// { iter_move(i) } -> same_as<iter_rvalue_reference_t<I>>;

Которые присутствовали (как комментарии в range/v3/iterator/concepts.hpp) даже до этого изменения реализации.

Однако, на самом деле, ни одно из этих требований не присутствует в работающем черновик [iterators.readable] диапазонов TS (ни в текущий HEAD ericniebler / stl2 , из которого генерируется предыдущий связанный черновик).

[iterators.readable] Концепция Readable

Концепция Readable удовлетворительная Типы, которые можно прочитать, применяя оператор *, включая указатели, умные указатели и итераторы.

template <class In>
concept bool Readable =
  requires {
    typename value_type_t<In>;
    typename reference_t<In>;
    typename rvalue_reference_t<In>;
  } &&
  CommonReference<reference_t<In>&&, value_type_t<In>&> &&
  CommonReference<reference_t<In>&&, rvalue_reference_t<In>&&> &&
  CommonReference<rvalue_reference_t<In>&&, const value_type_t<In>&>;

Может быть хорошей идеей сообщить об этом как о проблеме в По крайней мере, выясните, почему реализация range-v3 отличается от [iterators.readable] в диапазонах TS.

...