C++ 子数组模板
让我解释一下我在用代码寻找什么。让我们假设我们有一个包装数组的模板:C++ 子数组模板,c++,templates,C++,Templates,让我解释一下我在用代码寻找什么。让我们假设我们有一个包装数组的模板: 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::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]{};
};
我不希望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<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
如何实现上述效果?这解决了上述问题:
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>{} );
}
array\u视图
是讨论数组切片的一种简洁方式
如果你想迈步,你必须多做一些工作
我很确定使用std::integer\u序列的方法应该是可行的
这是:
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>
constexpr sub_array<START, COUNT> sub() {
static_assert(START + COUNT <= SIZE, "sub_array is out of range");
// The argument makes an instance of integer sequence from 0 to COUNT-1
return sub_impl<START, COUNT>(std::make_index_sequence<COUNT>{});
}
private:
template <std::size_t START, std::size_t COUNT, std::size_t ... Is>
constexpr sub_array<START, COUNT> sub_impl(std::index_sequence<Is...>) {
// Arithmetic in argument list expansion is pretty valid.
return {&data[Is+START]...};
}
};
模板
结构包裹
{
使用值_type=T;
使用wrap_type=wrap;
静态constexpr自动大小=大小;
T数据[大小]{};
模板
结构子数组
{
使用值类型=换行类型::值类型*;
静态constexpr自动启动=启动;
静态constexpr自动计数=计数;
值\类型数据[计数]{};
};
模板
constexpr sub_数组sub(){
static_assert(START+COUNT)作为实际数组的子数组不是string_view
中的视图。它是数组某些部分的副本。这些是不同的概念。请澄清您希望从sub()的返回值中得到什么确切属性
。属性是:使对象能够操作wrap
对象中包含的数组的子部分。我将去掉字符串视图
引用。您的设计将返回数组子部分的副本。对该子部分的更改不会反映在原始数组中,因为您创建了副本。Yo你在return{data[START+Is]…}中有一个小错误;
在我的方法中,我不是复制原始数组的一个片段,而是创建一个指向原始数组值的指针数组({&data[START+Is]…}
)所以最后我将能够通过指针修改原始数组。@PaperBirdMaster等等,哦,那太糟糕了。存储一堆不同于sizeof(T)的指针
是一种反模式;存储开始/结束指针将更简单、更高效,并且存储更少的无意义状态。嗯……我不知道你提到的那件事。我认为子数组中的每个地址都应该是有效的。为了启发我,你有关于这个主题的链接吗?@PaperBirdMaster>上面的array\u view
类型描述了我的意思。没有包含N个条目的数组,只有两个不同N的指针。
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>{} );
}
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]...};
}
);
}
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;
};
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>
constexpr sub_array<START, COUNT> sub() {
static_assert(START + COUNT <= SIZE, "sub_array is out of range");
// The argument makes an instance of integer sequence from 0 to COUNT-1
return sub_impl<START, COUNT>(std::make_index_sequence<COUNT>{});
}
private:
template <std::size_t START, std::size_t COUNT, std::size_t ... Is>
constexpr sub_array<START, COUNT> sub_impl(std::index_sequence<Is...>) {
// Arithmetic in argument list expansion is pretty valid.
return {&data[Is+START]...};
}
};
wrap<double, 10> ds{1,2,3,4,5,6,7,8,9,10};
auto s = ds.sub<2,3>();
std::cout << *s.data[0] << std::endl;