在索引和值类型上参数化的惯用矢量类型

时间:2021-10-24 16:25:30

Is there an idiomatic C++ type for a contiguous container that lets you specify both the value type (as std::vector and std::array do) and the index/size type?

是否存在一个连续容器的惯用C ++类型,它允许您指定值类型(如std :: vector和std :: array do)和索引/大小类型?

I've writing some code that going to manipulate a lot of arrays of data, but the indexes of the various arrays may have different semantic meanings, and I want to use the type system to prevent me from accidentally using an index in the wrong context.

我编写了一些代码来处理大量的数据数组,但各种数组的索引可能有不同的语义含义,我想使用类型系统来防止我在错误的上下文中意外使用索引。

For example, if I'm managing a collection of n hats, and m cars, I can give each hat ids from 0 up to n-1 and each car ids from 0 up to m-1 and have various arrays of hat and car information, but I wouldn't want to accidentally use a car id to look up something in an array of hat information.

例如,如果我正在管理一个n帽子和m个汽车的集合,我可以给每个帽子id从0到n-1并且每个车辆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

Right now I'm on the fence between taking the constant-time hit and using std::unordered_map or spending some dev time wrapping std::vector in a custom container class that adds a second parameter.

现在,我正处于持续时间命中和使用std :: unordered_map之间,或花费一些开发时间将std :: vector包装在添加第二个参数的自定义容器类中。

2 个解决方案

#1


3  

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?

是否存在一个连续容器的惯用C ++类型,它允许您指定值类型(如std :: vector does)和索引/大小类型?

No.


What you face here is a typical decision we have to take, weighing in the trade-off between spending development time VS using what STL already provides us with.

你在这里面对的是我们必须采取的典型决策,权衡利用STL已经为我们提供的开发时间VS之间的权衡。

In the first case you will have to spend some time, but hope to get better performance.

在第一种情况下,您将不得不花费一些时间,但希望获得更好的性能。

In the second case, your data structure is ready for use, but you may lose performance w.r.t. the data structure that you would have developed.

在第二种情况下,您的数据结构已准备就绪,但您可能会失去性能w.r.t.您将开发的数据结构。

As you know, std::unordered_map, provides constant query time, thus I were you, I would go on with this data structure (personalizing it as much as I want, by providing custom entities (e.g. CoryKramer suggest hashing in the comments), and when the project completes, test the performance and seek the bottleneck of it. If it is caused by the unordered map, then - depending on the circumstances of your time, which you may not know exactly now - take action and develop a custom data structure that will do the trick, if needed.

如你所知,std :: unordered_map提供了不断的查询时间,因此我就是你,我将继续使用这种数据结构(通过提供自定义实体(例如CoryKramer在评论中建议散列)来尽可能多地个性化它,当项目完成时,测试性能并寻找它的瓶颈。如果它是由无序的地图引起的,那么 - 根据您的时间情况,您现在可能不知道 - 完成行动并开发自定义数据如果需要的话,这个结构可以解决问题。

#2


0  

You may create a class for that, something like:

您可以为此创建一个类,例如:

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;
};

So with

class hat_id
{
public:
    explicit hat_id(int id) : id(id) {}
    explicit operator int() const { return id; }
private:
    int id;
};

// Equivalent for car_id

You may have:

你可能有:

car_id model_t {0};
typed_vector<hat_id, fabric> hat_materials { /*...*/ }
hat_materials[model_t]; // Would be an error here.

#1


3  

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?

是否存在一个连续容器的惯用C ++类型,它允许您指定值类型(如std :: vector does)和索引/大小类型?

No.


What you face here is a typical decision we have to take, weighing in the trade-off between spending development time VS using what STL already provides us with.

你在这里面对的是我们必须采取的典型决策,权衡利用STL已经为我们提供的开发时间VS之间的权衡。

In the first case you will have to spend some time, but hope to get better performance.

在第一种情况下,您将不得不花费一些时间,但希望获得更好的性能。

In the second case, your data structure is ready for use, but you may lose performance w.r.t. the data structure that you would have developed.

在第二种情况下,您的数据结构已准备就绪,但您可能会失去性能w.r.t.您将开发的数据结构。

As you know, std::unordered_map, provides constant query time, thus I were you, I would go on with this data structure (personalizing it as much as I want, by providing custom entities (e.g. CoryKramer suggest hashing in the comments), and when the project completes, test the performance and seek the bottleneck of it. If it is caused by the unordered map, then - depending on the circumstances of your time, which you may not know exactly now - take action and develop a custom data structure that will do the trick, if needed.

如你所知,std :: unordered_map提供了不断的查询时间,因此我就是你,我将继续使用这种数据结构(通过提供自定义实体(例如CoryKramer在评论中建议散列)来尽可能多地个性化它,当项目完成时,测试性能并寻找它的瓶颈。如果它是由无序的地图引起的,那么 - 根据您的时间情况,您现在可能不知道 - 完成行动并开发自定义数据如果需要的话,这个结构可以解决问题。

#2


0  

You may create a class for that, something like:

您可以为此创建一个类,例如:

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;
};

So with

class hat_id
{
public:
    explicit hat_id(int id) : id(id) {}
    explicit operator int() const { return id; }
private:
    int id;
};

// Equivalent for car_id

You may have:

你可能有:

car_id model_t {0};
typed_vector<hat_id, fabric> hat_materials { /*...*/ }
hat_materials[model_t]; // Would be an error here.