在索引和值类型上参数化的惯用向量类型
Idiomatic vector-like type parameterized over index and value types
是否有用于连续容器的惯用 C++ 类型,可让您同时指定值类型(如 std::vector
和 std::array
所做的那样)和 index/size 类型?
我写了一些代码来操作很多数据数组,但是各种数组的索引可能有不同的语义,我想使用类型系统来防止我不小心使用在错误的上下文中索引。
例如,如果我正在管理 n
顶帽子和 m
辆汽车的集合,我可以为每顶帽子提供从 0
到 n-1
的 ID并且每辆汽车 ID 从 0
到 m-1
并且具有各种帽子和汽车信息数组,但我不想不小心使用汽车 ID 来查找帽子信息数组中的内容。
car_id model_t {0};
my::vector<hat_id, fabric> hat_materials { /*...*/ }
hat_materials[model_t]; // want this to be a compile error
现在我在采取恒定时间点击和使用 std::unordered_map
或花费一些开发时间将 std::vector
包装在自定义容器 class 之间犹豫不决第二个参数.
Is there an idiomatic C++ type for a contiguous container that lets you specify both the value type (as std::vector
does) and the index/size type?
没有.
您在这里面临的是我们必须做出的典型决定,权衡花费开发时间与使用 STL 已经提供给我们的东西之间的权衡。
第一种情况需要花费一些时间,但希望获得更好的性能。
在第二种情况下,您的数据结构可以使用,但您可能会损失性能w.r.t。你会开发的数据结构。
如您所知,std::unordered_map
提供恒定的查询时间,因此我就是您,我会继续使用此数据结构(通过提供自定义实体(例如 CoryKramer 建议hashing in the comments),等项目完成后,测试一下性能,寻找它的bottleneck,如果是无序map导致的,那么——看你当时的情况,您现在可能还不完全了解 - 采取行动并开发一个自定义数据结构,如果需要的话,它可以解决问题。
您可以为此创建一个 class,例如:
template <typename IndexT, typename T>
class typed_vector
{
public:
typed_vector() = default;
typed_vector(const typed_vector&) = default;
typed_vector(typed_vector&&) = default;
typed_vector& operator=(const typed_vector&) = default;
typed_vector& operator=(typed_vector&&) = default;
template <typename ... U,
typename ... Ts,
std::enable_if_t<sizeof...(Ts) == 0
|| !std::is_same<std::decay_t<U>>::value,
typed_vector>* = nullptr>
typed_vector(U&& u, Ts&&...args) : mData(std::forward<Ts>(args)...) {}
typed_vector(std::initializer_list<T> ini) : mData(ini) {}
// The safe array subscript
const T& operator[](IndexT index) const {
return mData[static_cast<int>(index)];
}
T& operator[](IndexT index) { return mData[static_cast<int>(index)]; }
// ...
private:
std::vector<T> mData;
};
所以
class hat_id
{
public:
explicit hat_id(int id) : id(id) {}
explicit operator int() const { return id; }
private:
int id;
};
// Equivalent for car_id
您可能有:
car_id model_t {0};
typed_vector<hat_id, fabric> hat_materials { /*...*/ }
hat_materials[model_t]; // Would be an error here.
是否有用于连续容器的惯用 C++ 类型,可让您同时指定值类型(如 std::vector
和 std::array
所做的那样)和 index/size 类型?
我写了一些代码来操作很多数据数组,但是各种数组的索引可能有不同的语义,我想使用类型系统来防止我不小心使用在错误的上下文中索引。
例如,如果我正在管理 n
顶帽子和 m
辆汽车的集合,我可以为每顶帽子提供从 0
到 n-1
的 ID并且每辆汽车 ID 从 0
到 m-1
并且具有各种帽子和汽车信息数组,但我不想不小心使用汽车 ID 来查找帽子信息数组中的内容。
car_id model_t {0};
my::vector<hat_id, fabric> hat_materials { /*...*/ }
hat_materials[model_t]; // want this to be a compile error
现在我在采取恒定时间点击和使用 std::unordered_map
或花费一些开发时间将 std::vector
包装在自定义容器 class 之间犹豫不决第二个参数.
Is there an idiomatic C++ type for a contiguous container that lets you specify both the value type (as
std::vector
does) and the index/size type?
没有.
您在这里面临的是我们必须做出的典型决定,权衡花费开发时间与使用 STL 已经提供给我们的东西之间的权衡。
第一种情况需要花费一些时间,但希望获得更好的性能。
在第二种情况下,您的数据结构可以使用,但您可能会损失性能w.r.t。你会开发的数据结构。
如您所知,std::unordered_map
提供恒定的查询时间,因此我就是您,我会继续使用此数据结构(通过提供自定义实体(例如 CoryKramer 建议hashing in the comments),等项目完成后,测试一下性能,寻找它的bottleneck,如果是无序map导致的,那么——看你当时的情况,您现在可能还不完全了解 - 采取行动并开发一个自定义数据结构,如果需要的话,它可以解决问题。
您可以为此创建一个 class,例如:
template <typename IndexT, typename T>
class typed_vector
{
public:
typed_vector() = default;
typed_vector(const typed_vector&) = default;
typed_vector(typed_vector&&) = default;
typed_vector& operator=(const typed_vector&) = default;
typed_vector& operator=(typed_vector&&) = default;
template <typename ... U,
typename ... Ts,
std::enable_if_t<sizeof...(Ts) == 0
|| !std::is_same<std::decay_t<U>>::value,
typed_vector>* = nullptr>
typed_vector(U&& u, Ts&&...args) : mData(std::forward<Ts>(args)...) {}
typed_vector(std::initializer_list<T> ini) : mData(ini) {}
// The safe array subscript
const T& operator[](IndexT index) const {
return mData[static_cast<int>(index)];
}
T& operator[](IndexT index) { return mData[static_cast<int>(index)]; }
// ...
private:
std::vector<T> mData;
};
所以
class hat_id
{
public:
explicit hat_id(int id) : id(id) {}
explicit operator int() const { return id; }
private:
int id;
};
// Equivalent for car_id
您可能有:
car_id model_t {0};
typed_vector<hat_id, fabric> hat_materials { /*...*/ }
hat_materials[model_t]; // Would be an error here.