Итератор Constexpr в C ++ - PullRequest
       32

Итератор Constexpr в C ++

0 голосов
/ 26 октября 2018

Я заинтересован в создании очень минимального контейнера constexpr для личного проекта. Самое главное, что мне нужно, - это контейнер с настоящими итераторами constexpr. В конечном итоге они будут добавлены в стандарт (http://www.open -std.org / jtc1 / sc22 / wg21 / docs / paper / 2018 / p0858r0.html ), но я хотел бы знать, как реализовать их в текущем C ++.

Допустим, у меня была такая структура данных:

template <typename T, unsigned N>
struct array {
  const T data[N];

  template<typename... Args>
  constexpr array(const Args&... args) : data{args...} {
}
  struct array_iterator {
    T const* ptr;

    constexpr array_iterator(const T* ptr) : ptr(ptr) {}

    constexpr void operator++() { ++ptr; }
    constexpr void operator--() { --ptr; }
    constexpr T const& operator* () const { return *ptr; }
    constexpr bool operator==(const array_iterator& rhs) const { return *(*this) == *rhs; }
    constexpr bool operator!=(const array_iterator& rhs) const { return !(*this == rhs); }
  };

  constexpr array_iterator begin() const { return array_iterator(data); }
  constexpr array_iterator end()   const { return array_iterator(data + N); }
};

Мне нужно иметь возможность использовать итераторы в контексте constexpr:

constexpr array<int, 3> arr(1, 2, 3);
constexpr auto it = arr.begin();

Но, очевидно, поскольку я возился с подобъектом non-constexpr ptr, я сталкиваюсь с такими ошибками:

iterator.cpp:46:18: error: constexpr variable 'it' must be initialized by a
      constant expression
  constexpr auto it = arr.begin();
                 ^    ~~~~~~~~~~~
iterator.cpp:46:18: note: pointer to subobject of 'arr' is not a constant
      expression
iterator.cpp:45:27: note: declared here
  constexpr array<int, 3> arr(1, 2, 3);
                          ^

Так что же будет минимальным итератором constexpr для контейнера, подобного массиву?

1 Ответ

0 голосов
/ 26 октября 2018

constexpr имеет несколько значений.

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

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

template <typename T, unsigned N>
struct array {
  const T data[N];

  template<typename... Args>
  constexpr array(const Args&... args) : data{args...} {}

  struct array_iterator {
    T const* ptr;

    constexpr array_iterator(const T* ptr) : ptr(ptr) {}

    constexpr void operator++() { ++ptr; }
    constexpr void operator--() { --ptr; }
    constexpr T const& operator* () const { return *ptr; }
    constexpr bool operator==(const array_iterator& rhs) const { return ptr == rhs.ptr; }
    constexpr bool operator!=(const array_iterator& rhs) const { return !(*this == rhs); }
  };

  constexpr array_iterator begin() const { return array_iterator(data); }
  constexpr array_iterator end()   const { return array_iterator(data + N); }
};

constexpr int sum() {
    int retval = 0;
    constexpr array<int, 3> arr = {1,2,3};
    for (int x : arr)
        retval += x;
    return retval;
}

int main() {
    array<int, sum()> test;
    (void)test;
}

ваш operator== был сломан, но после исправления мы можем вызвать sum() в контексте constexpr, который, в свою очередь, использует итераторы.

...