【问题标题】:constexpr vector push_back or how to constexpr all the thingsconstexpr 矢量 push_back 或如何 constexpr 所有的东西
【发布时间】:2019-04-30 03:44:13
【问题描述】:

来自 C++Now 2017 的 Jason Turner 和 Ben Deane 有一个很好的演讲,称为 constexpr All the things,它还提供了一个 constexpr 向量实现。出于教育目的,我自己也在尝试这个想法。我的 constexpr 向量是纯粹的,因为推回它会返回一个带有添加元素的新向量。

在谈话中,我看到了一个push_back 的实现,看起来或多或少如下:

constexpr void push_back(T const& e) {
    if(size_ >= Size)
       throw std::range_error("can't use more than Size");
    else {
        storage_[size_++] = e;
    }
} 

他们按价值获取元素并移动它,但我不认为这是我的问题的根源。我想知道的是,如何在 constexpr 上下文中使用此函数?这不是一个 const 成员函数,它会修改状态。我认为有可能做类似的事情

constexpr cv::vector<int> v1;
v1.push_back(42);

如果这是不可能的,我们如何在 constexpr 上下文中使用这个东西并使用这个向量来实现任务的目标,即编译时 JSON 解析?

这是我的版本,所以你可以看到我的新矢量返回版本和谈话中的版本。 (注意性能、完美转发等问题都省略了)

#include <cstdint>
#include <array>
#include <type_traits>

namespace cx {
template <typename T, std::size_t Size = 10>
struct vector {
    using iterator = typename std::array<T, Size>::iterator;
    using const_iterator = typename std::array<T, Size>::const_iterator;

    constexpr vector(std::initializer_list<T> const& l) {
        for(auto& t : l) {
            if(size_++ < Size)
                storage_[size_] = std::move(t);
            else
                break;
        }
    }

    constexpr vector(vector const& o, T const& t) {
        storage_ = o.storage_;
        size_ = o.size_;
        storage_[size_++] = t;
    }

    constexpr auto begin() const { return storage_.begin(); }
    constexpr auto end()  const { return storage_.begin() + size_; }
    constexpr auto size() const { return size_; }

    constexpr void push_back(T const& e) {
        if(size_ >= Size)
            throw std::range_error("can't use more than Size");
        else {
            storage_[size_++] = e;
        }
    }

    std::array<T, Size> storage_{};
    std::size_t size_{};
};
}

template <typename T>
constexpr auto make_vector(std::initializer_list<T> const& l) {
    return cx::vector<int>{l};
}

template <typename T>
constexpr auto push_back(cx::vector<T> const& o, T const& t) {
    return cx::vector<int>{o, t};
}

int main() {
    constexpr auto v1 = make_vector({1, 2, 3});
    static_assert(v1.size() == 3);
    constexpr auto v2 = push_back(v1, 4);
    static_assert(v2.size() == 4);

    static_assert(std::is_same_v<decltype(v1), decltype(v2)>);

    // v1.push_back(4); fails on a constexpr context
} 

所以,这件事让我意识到我可能对 constexpr 有一些深层次的了解。所以,回顾一下这个问题;这样的 constexpr 向量如何在 constexpr 上下文中提供像这样的变异push_back?似乎它现在不能在 constexpr 上下文中工作。如果 constexpr 上下文中的 push_back 不打算以开头,那么如何将其称为 constexpr 向量并将其用于编译时 JSON 解析?

【问题讨论】:

  • 可以在 constexpr 函数中创建和返回非 constexpr 值,并用于在 constexpr 函数之外初始化 constexpr 变量。

标签: c++ constexpr


【解决方案1】:

您对向量的定义是正确的,但您不能修改constexpr 对象。它们很好,而且确实是恒定的。相反,在constexpr 函数内进行编译时计算(然后可以将其输出分配给constexpr 对象)。

例如,我们可以编写一个函数range,它产生一个从0n 的数字向量。它使用push_back,我们可以将结果分配给main 中的constexpr 向量。

constexpr vector<int> range(int n) {
    vector<int> v{};
    for(int i = 0; i < n; i++) {
        v.push_back(i); 
    }
    return v; 
}

int main() {
    constexpr vector<int> v = range(10);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-21
    • 2021-08-15
    • 2015-05-04
    • 2016-09-27
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多