如果我有一個包含N個大小相等的vectors
的類。我將如何去實現一個標準的迭代器模板,它將在1到N個矢量之間迭代。我寫了一個小例子來說明問題。如何爲其中包含N個向量的類實現子集迭代器
#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
}
}
如何處理沒有初始化的「缺失」數據(通過標記?)如果缺少的元素在迭代的範圍內不均勻,你會怎麼做?你見過boost zip迭代器嗎?我猜你只需要'(:)'基於範圍的循環迭代? – Yakk
對不起,沒有解釋「缺少」數據的行爲。我想跳過那個插槽。我希望'for(:)'爲基礎的循環,併爲完整for循環的迭代器成員。 – Brian