gpt4 book ai didi

c++ - 如何为其中包含 N 个 vector 的类实现子集迭代器

转载 作者:行者123 更新时间:2023-11-30 02:28:17 25 4
gpt4 key购买 nike

如果我有一个包含 N 个大小相同的 vectors 的类。我将如何实现一个标准的迭代器模板,该模板将在 1 到 N 个 vector 之间迭代。我写了一个小例子来演示这个问题。

#include <bitset>
#include <tuple>
#include <type_traits>
#include <vector>

//Since std::get<>() for types isn't in c++11, I use this meta-function to determine the index
//of a Type in a list of Types, starting from 0. ex: IndexOf<C, A, B, C>::value = 2
template <typename T, typename... Ts>
struct IndexOf;

template <typename T, typename... Ts>
struct IndexOf<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};

template <typename T, typename U, typename... Ts>
struct IndexOf<T, U, Ts...> : std::integral_constant<std::size_t, 1 + IndexOf<T, Ts...>::value> {};

//Used to determine the slot we're interesting in.
using Handle = const std::size_t;

template<typename... Types>
class DataManager
{
static constexpr std::size_t TypeCount = sizeof... (Types);
using Flags = std::bitset<TypeCount>; //BitMask to determine if the handle has a certain piece of data initialized

std::size_t count, capacity;
std::tuple<std::vector<Types>..., std::vector<Flags>> vectors; //Tuple of vectors, holding the types and flags.
public:
DataManager(std::size_t n) : count(0), capacity(n),
vectors(std::make_tuple(std::vector<Types>(n)..., std::vector<Flags>(n)))
{}

template <typename Type, typename... Args>
void add(Handle handle, Args&&... args) { //Initializes the type in the handle slot of the vector
Flags& flags = std::get<TypeCount>(vectors)[handle]; //Flag the bit, notify that handle
flags.set(IndexOf<Type, Types...>::value); //has that piece of data initialized

std::get<IndexOf<Type, Types...>::value>(vectors)[handle] = Type{ args... };
}

template <typename Type>
Type& get(Handle handle) { //Returns the Type in handle slot of the vector
return std::get<IndexOf<Type, Types...>::value>(vectors)[handle];
}

template <typename Type>
bool has(Handle handle) { //Returns true if the Type is initialized, by checking the bitset
Flags& flags = std::get<TypeCount>(vectors)[handle];
return flags.test(IndexOf<Type, Types...>::value);
}

Handle push_back() {
return count++;
}
};

我目前使用它来访问数据:

//Simple Data
struct D0 { int x, y; };
struct D1 { float n, m; };
struct D2 { int x, y, z; };

int main()
{
DataManager<D0, D1, D2> manager(100);
Handle h0 = manager.push_back();

std::cout << manager.has<D0>(h0) << std::endl; //prints false, h0 doesn't have D0 initialized
manager.add<D0>(h0, 75, 20); //initialize D0 for h0

std::cout << manager.has<D0>(h0) << std::endl; //prints ture, h0 is now initialzed
std::cout << manager.get<D0>(h0).x << std::endl; //prints 75
}

我如何向 DataManager 类添加迭代器功能,它只会像这样迭代选定的数据?

 int main() 
{
...
for (D0 d1, D3 d3 : manager) {
... //Iterate over all D0s and D3s between 0 and count
}
//or
for(DataManager<D0>::iterator it = v.begin(); it != v.end(); ++it {
... //Iterate over just D0s between 0 and count - 10
}
}

最佳答案

编写范围 View 类型。范围 View 有两个迭代器,一个开始和一个结束,并公开 .begin().end() 。返回迭代器的范围 View 可让您在不复制任何内容的情况下执行 for(:) 循环。

接下来您需要一个遍历所选元素的迭代器。我可以想到两种方法。

首先,一个 zip 迭代器。一个 zip 迭代器有一个迭代器元组,并并行推进它们。当您取消引用时,它会返回每个迭代器的取消引用的 std::tie

第二个选项,生成器迭代器。生成器迭代器有一个索引,以及一个从索引映射到某种类型的函数。 ++== 等只是推进/比较索引。 * 返回函数调用的结果。在这种情况下,您将从该函数返回 tie

我通常通过从索引迭代器(存储索引,* 返回它的拷贝)开始实现生成器迭代器,然后编写转换迭代器(存储迭代器,将 ==++ 等转发给它,存储一个函数 f ,并且在 * 上执行 f(*it) ,其中 it 是存储的迭代器)。生成器迭代器现在只是一个 transform_iterator<F(index_iterator)>


由于围绕 ::reference 类型等的规则,这些都有效地限于满足输入迭代器的公理。但是,输入迭代器足以执行 for(:) 循环;此外,for(:) 循环甚至不需要合法的迭代器,因为它是根据代码而非迭代器语义定义的。


生成器/转换迭代器就足够了,而且两者在其他情况下都很有用,所以我会采用这种方法。

如果需要,您可以选择类型删除转换(转换为 std::function< T(std::size_t) > )。

template<class T>
using any_generator_iterator = transform_iterator< std::function<T(std::size_t)>( indexing_iterator ) >;

现在迭代类型 A B 和 C 我们这样做:

template<class...Ts,
class R=std::tuple<Ts&...>,
class It=any_generator_iterator<R>
>
range_view< It >
iterate_over() {
auto get = [this](std::size_t i)->R {
return std::tie( this->get<Ts>()... );
};
return { {get, 0}, {{}, count} };
}

别处:

for( auto i : foo.iterate_over<A,B,C>() ) {
auto&& a = std::get<0>(i);
auto&& b = std::get<1>(i);
auto&& c = std::get<2>(i);
// code
}

上面有一堆库代码。

大部分(如果不是全部)已在 boost 中解决。

关于c++ - 如何为其中包含 N 个 vector 的类实现子集迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40897011/

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