【问题标题】:Constexpr Iterator in C++C++ 中的 Consexpr 迭代器
【发布时间】:2018-10-26 17:23:06
【问题描述】:

我有兴趣为个人项目创建一个非常小的 constexpr 容器。我需要的最重要的东西是一个带有真正 constexpr 迭代器的容器。它们最终将被添加到标准中(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/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();

但很明显,由于我在搞乱非 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 迭代器?

【问题讨论】:

  • 你只需要将arr设为静态:static constexpr array&lt;int, 3&gt; arr(1, 2, 3);
  • 这确实有效!但不幸的是,如果您在 constexpr 函数中,则无法将变量设为静态,这是我认为这种类型的数据结构最有用的地方。

标签: c++ templates c++17 template-meta-programming constexpr


【解决方案1】:

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== 已损坏,但修复后我们可以在constexpr 上下文中调用sum(),而后者又使用迭代器。

【讨论】:

  • 有什么方法可以创建一个可以引用自动存储 constexpr 对象的迭代器,还是需要运行时计算?
  • @SamG 引用和指向自动存储持续时间对象的指针不是constexpr。考虑;你能把它传递给一个模板并在那里使用它的身份吗?我的意思是,您可以创建包含它们正在迭代的数组的完整副本的迭代器,并根据数组的身份和其中的位置来衡量身份。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-30
  • 1970-01-01
  • 1970-01-01
  • 2014-03-21
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
相关资源
最近更新 更多