gpt4 book ai didi

c++ - 子数组模板

转载 作者:搜寻专家 更新时间:2023-10-31 02:13:46 26 4
gpt4 key购买 nike

让我用代码解释一下我在寻找什么。假设我们有一个包装数组的模板:

template <typename T, std::size_t SIZE>
struct wrap
{
using value_type = T;
using wrap_type = wrap;

static constexpr auto size = SIZE;
T data[size]{};
};

我想在wrap 模板中添加一个函数,该函数应该返回一个对象,该对象能够操作包含在wrap 中的数组的特定部分,该函数应该知道子数组从哪里开始以及它将包含多少元素,所以我想到了这样一个函数:

template <typename T, std::size_t SIZE>
struct wrap
{
using value_type = T;
using wrap_type = wrap;

static constexpr auto size = SIZE;
T data[size]{};

template <std::size_t START, std::size_t COUNT>
???? sub() { ... }
};

我不希望 wrap::sub 返回的 ???? 对象有几个指针,而是一个静态数组,所以我的方法是:

template <typename T, std::size_t SIZE>
struct wrap
{
using value_type = T;
using wrap_type = wrap;

static constexpr auto size = SIZE;
T data[size]{};

template <std::size_t START, std::size_t COUNT>
struct sub_array
{
using value_type = wrap_type::value_type *;

static constexpr auto start = START;
static constexpr auto count = COUNT;

value_type data[count]{};
};

template <std::size_t START, std::size_t COUNT>
sub_array<START, COUNT> sub() { ... }
};

问题来了:我应该在 wrap::sub 中写入什么?我很确定使用 std::integer_sequence 的方法应该是可能的,但我缺乏经验,因此我什至不知道该尝试什么。我尝试使用 wrap::sub 中的两个模板参数假设一个 2 的值,它按预期工作:

template <std::size_t START, std::size_t SIZE>
sub_array<START, SIZE> sub() { return { &data[START], &data[START + 1u] }; }

我已经测试了它,如下所示:

wrap<int, 9> w{1, 2, 3, 4, 5, 6, 7, 8, 9};

// x is the view [3, 4]
auto x = w.sub<2, 2>();

std::cout << *x.data[0] << '\n'; // shows 3

因此,从概念上讲,wrap::sub 的主体应该是:

return { &data[START + 0], &data[START + 1], ... &data[START + n] };

如何实现上面的效果?

最佳答案

这解决了上述问题:

template<class=void, std::size_t...Is>
auto indexer( std::index_sequence<Is...> ) {
return [](auto&& f){
return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N>
auto indexer() {
return indexer( std::make_index_sequence<N>{} );
}

这使您可以创建一个可扩展的编译时整数参数包,而不必每次都编写自定义辅助函数。

它是有效的 C++14,但一些编译器(如 MSVC)声称是 C++14 编译器,但实际上并不是 C++14 编译器。

template <std::size_t START, std::size_t SIZE>
sub_array<START, SIZE> sub() const {
auto index = indexer<SIZE>();
return index(
[&](auto...Is)->sub_array<START, SIZE>
{
return {data[START+Is]...};
}
);
}

indexer<N>返回一个索引器,当传递一个 lambda 时,用 std::integral_constant<std::size_t, 0> 调用它通过std::integral_constant<std::size_t, N-1> .

然后可以在创建 indexer 的函数中内联扩展此包.


在您提到的评论中,您希望对子数组的修改反射(reflect)在原始数组中。

您的设计不允许这样做。子数组是原始数组切片的拷贝。

正确的做法是让子数组成为指向原始数组的一对指针。

template<class T>
struct array_view {
T* b = 0;
T* e = 0;

T* begin() const { return b; }
T* end() const { return e; }

T& operator[](std::size_t i)const { return begin()[i]; }

bool empty() const { return begin()==end(); }
std::size_t size() const { return end()-begin(); }

array_view( T* s, T* f ):b(s), e(f) {}
array_view( T* s, std::size_t l):array_view(s, s+l) {}

array_view()=default;
array_view(array_view const&)=default;
array_view& operator=(array_view const&)=default;
};

array_view是讨论数组切片的一种紧凑方式。

如果你想要进步,你必须做更多的工作。

关于c++ - 子数组模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40892890/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com