你不应该继承 std::vector

发布于 2024-10-06 15:19:30 字数 799 浏览 1 评论 0原文

好吧,这确实很难承认,但我现在确实有强烈的诱惑要继承 std::vector

我需要大约 10 个向量的自定义算法,并且我希望它们直接成为向量的成员。但我自然也希望拥有 std::vector 接口的其余部分。好吧,作为一个守法公民,我的第一个想法是在 MyVector 类中拥有一个 std::vector 成员。但随后我必须手动重新提供所有 std::vector 的接口。太多打字了。接下来,我考虑了私有继承,这样我就可以在公共部分编写一堆 using std::vector::member ,而不是重新提供方法。这其实也很乏味。

在这里,我确实认为我可以简单地从 std::vector 公开继承,但在文档中提供警告,表明此类不应以多态方式使用。我认为大多数开发人员都有足够的能力理解这无论如何都不应该被多态地使用。

我的决定绝对不合理吗?如果是这样,为什么?您能否提供一种替代方案,让其他成员实际上成为成员,但不会涉及重新输入所有向量的接口?我对此表示怀疑,但如果可以的话,我会很高兴。

另外,除了某些白痴可以写出类似的东西之外,

std::vector<int>* p  = new MyVector

使用 MyVector 还存在其他现实危险吗?通过说现实,我放弃了诸如想象一个带有指向向量的指针的函数之类的东西......

好吧,我已经陈述了我的情况。我犯了罪。现在就看你是否原谅我了:)

Ok, this is really difficult to confess, but I do have a strong temptation at the moment to inherit from std::vector.

I need about 10 customized algorithms for vector and I want them to be directly members of the vector. But naturally I want also to have the rest of std::vector's interface. Well, my first idea, as a law-abiding citizen, was to have an std::vector member in MyVector class. But then I would have to manually reprovide all of the std::vector's interface. Too much to type. Next, I thought about private inheritance, so that instead of reproviding methods I would write a bunch of using std::vector::member's in the public section. This is tedious too actually.

And here I am, I really do think that I can simply inherit publicly from std::vector, but provide a warning in the documentation that this class should not be used polymorphically. I think most developers are competent enough to understand that this shouldn't be used polymorphically anyway.

Is my decision absolutely unjustifiable? If so, why? Can you provide an alternative which would have the additional members actually members but would not involve retyping all of vector's interface? I doubt it, but if you can, I'll just be happy.

Also, apart from the fact that some idiot can write something like

std::vector<int>* p  = new MyVector

is there any other realistic peril in using MyVector? By saying realistic I discard things like imagine a function which takes a pointer to vector ...

Well, I've stated my case. I have sinned. Now it's up to you to forgive me or not :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

迷迭香的记忆 2024-10-13 15:19:30

实际上,std::vector 的公共继承并没有什么问题。如果你需要这个,就这么做吧。

我建议仅在确实必要时才这样做。仅当您无法使用自由函数执行您想要的操作时(例如应该保留某些状态)。

问题在于 MyVector 是一个新实体。这意味着新的 C++ 开发人员在使用它之前应该知道它到底是什么。 std::vectorMyVector 有什么区别?到处使用哪一个更好?如果我需要将 std::vector 移动到 MyVector 该怎么办?我可以只使用 swap() 吗?

不要仅仅为了让某些东西看起来更好而产生新的实体。这些实体(尤其是常见的实体)不会生活在真空中。他们将生活在熵不断增加的混合环境中。

Actually, there is nothing wrong with public inheritance of std::vector. If you need this, just do that.

I would suggest doing that only if it is really necessary. Only if you can't do what you want with free functions (e.g. should keep some state).

The problem is that MyVector is a new entity. It means a new C++ developer should know what the hell it is before using it. What's the difference between std::vector and MyVector? Which one is better to use here and there? What if I need to move std::vector to MyVector? May I just use swap() or not?

Do not produce new entities just to make something to look better. These entities (especially, such common) aren't going to live in vacuum. They will live in mixed environment with constantly increased entropy.

得不到的就毁灭 2024-10-13 15:19:30

整个STL的设计方式是算法和容器是分离的

这导致了不同类型迭代器的概念:const 迭代器、随机访问迭代器等。

因此,我建议您接受此约定并以这样的方式设计您的算法:它们不会关心它们的容器是什么。正在研究 - 他们只需要执行操作所需的特定类型的迭代器。

另外,让我将您重定向到Jeff Attwood 的一些精彩评论< /strong>

The whole STL was designed in such way that algorithms and containers are separate.

This led to a concept of different types of iterators: const iterators, random access iterators, etc.

Therefore I recommend you to accept this convention and design your algorithms in such way that they won't care about what is the container they're working on - and they would only require a specific type of iterator which they'd need to perform their operations.

Also, let me redirect you to some good remarks by Jeff Attwood.

甩你一脸翔 2024-10-13 15:19:30

不公开继承 std::vector 的主要原因是缺少虚拟析构函数,该析构函数有效地阻止您对后代进行多态使用。特别是,您不允许删除 std::vector* 实际上指向派生对象(即使派生类没有添加任何成员),但编译器通常无法警告您这一点。

在这些条件下允许私人继承。因此,我建议使用私有继承并从父级转发所需的方法,如下所示。

class AdVector: private std::vector<double>
{
    typedef double T;
    typedef std::vector<double> vector;
public:
    using vector::push_back;
    using vector::operator[];
    using vector::begin;
    using vector::end;
    AdVector operator*(const AdVector & ) const;
    AdVector operator+(const AdVector & ) const;
    AdVector();
    virtual ~AdVector();
};

正如大多数回答者所指出的那样,您应该首先考虑重构您的算法以抽象它们正在操作的容器类型,并将它们保留为免费模板化函数。这通常是通过使算法接受一对迭代器而不是容器作为参数来完成的。

The main reason for not inheriting from std::vector publicly is an absence of a virtual destructor that effectively prevents you from polymorphic use of descendants. In particular, you are not allowed to delete a std::vector<T>* that actually points at a derived object (even if the derived class adds no members), yet the compiler generally can't warn you about it.

Private inheritance is allowed under these conditions. I therefore recommend using private inheritance and forwarding required methods from the parent as shown below.

class AdVector: private std::vector<double>
{
    typedef double T;
    typedef std::vector<double> vector;
public:
    using vector::push_back;
    using vector::operator[];
    using vector::begin;
    using vector::end;
    AdVector operator*(const AdVector & ) const;
    AdVector operator+(const AdVector & ) const;
    AdVector();
    virtual ~AdVector();
};

You should first consider refactoring your algorithms to abstract the type of container they are operating on and leave them as free templated functions, as pointed out by majority of answerers. This is usually done by making an algorithm accept a pair of iterators instead of container as arguments.

不喜欢何必死缠烂打 2024-10-13 15:19:30

如果你正在考虑这一点,那么你显然已经消灭了办公室里的语言学究。有了它们,为什么不直接这样做呢?

struct MyVector
{
   std::vector<Thingy> v;  // public!
   void func1( ... ) ; // and so on
}

这将避免由于意外升级 MyVector 类而可能出现的所有可能的错误,并且您仍然可以通过添加一点 .v .

If you're considering this, you've clearly already slain the language pedants in your office. With them out of the way, why not just do

struct MyVector
{
   std::vector<Thingy> v;  // public!
   void func1( ... ) ; // and so on
}

That will sidestep all the possible blunders that might come out of accidentally upcasting your MyVector class, and you can still access all the vector ops just by adding a little .v .

活泼老夫 2024-10-13 15:19:30

您希望实现什么目标?只是提供一些功能吗?

C++ 惯用的方法是编写一些实现该功能的自由函数。很可能您实际上并不需要 std::vector,特别是您正在实现的功能,这意味着您实际上通过尝试从 std::vector 继承而失去了可重用性。

我强烈建议您查看标准库和标头,并思考它们是如何工作的。

What are you hoping to accomplish? Just providing some functionality?

The C++ idiomatic way to do this is to just write some free functions that implement the functionality. Chances are you don't really require a std::vector, specifically for the functionality you're implementing, which means you're actually losing out on reusability by trying to inherit from std::vector.

I would strongly advise you to look at the standard library and headers, and meditate on how they work.

浅浅淡淡 2024-10-13 15:19:30

我认为很少有规则应该在 100% 的情况下盲目遵循。听起来你已经考虑了很多,并且确信这是正确的方法。因此,除非有人提出不这样做的良好具体理由,否则我认为您应该继续执行您的计划。

I think very few rules should be followed blindly 100% of the time. It sounds like you've given it quite a lot of thought, and are convinced that this is the way to go. So -- unless someone comes up with good specific reasons not to do this -- I think you should go ahead with your plan.

飘过的浮云 2024-10-13 15:19:30

没有理由从 std::vector 继承,除非想要创建一个与 std::vector 工作方式不同的类,因为它以自己的方式处理隐藏的std::vector 定义的详细信息,或者除非出于意识形态原因使用此类的对象来代替 std::vector 的对象。然而,C++ 标准的创建者没有为 std::vector 提供任何接口(以受保护成员的形式),此类继承类可以利用该接口来改进向量。具体方式。事实上,他们无法考虑可能需要扩展或微调额外实现的任何特定方面,因此他们不需要考虑为任何目的提供任何此类接口。

第二个选项的原因可能只是意识形态上的,因为 std::vector 不是多态的,否则无论您公开 std::vector 都没有区别通过公共继承或公共成员资格的公共接口。 (假设您需要在对象中保留某些状态,这样您就无法摆脱自由函数的束缚)。从不太合理的角度来看,从意识形态的角度来看,std::vector 似乎是一种“简单的想法”,因此不同可能类的对象形式的任何复杂性他们在意识形态上的地位毫无用处。

There is no reason to inherit from std::vector unless one wants to make a class that works differently than std::vector, because it handles in its own way the hidden details of std::vector's definition, or unless one has ideological reasons to use the objects of such class in place of std::vector's ones. However, the creators of the standard on C++ did not provide std::vector with any interface (in the form of protected members) that such inherited class could take advantage of in order to improve the vector in a specific way. Indeed, they had no way to think of any specific aspect that might need extension or fine-tune additional implementation, so they did not need to think of providing any such interface for any purpose.

The reasons for the second option can be only ideological, because std::vectors are not polymorphic, and otherwise there is no difference whether you expose std::vector's public interface via public inheritance or via public membership. (Suppose you need to keep some state in your object so you cannot get away with free functions). On a less sound note and from the ideological point of view, it appears that std::vectors are a kind of "simple idea", so any complexity in the form of objects of different possible classes in their place ideologically makes no use.

梦罢 2024-10-13 15:19:30

实际上:如果派生类中没有任何数据成员,则不会有任何问题,即使在多态使用中也是如此。仅当基类和派生类的大小不同和/或您有虚拟函数(这意味着 v 表)时,您才需要虚拟析构函数。

但理论上:来自C++0x FCD中的[expr.delete]:在第一个替代方案(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,静态类型应是要删除的对象的动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。

但是您可以毫无问题地从 std::vector 导出。
我使用了以下模式:

class PointVector : private std::vector<PointType>
{
    typedef std::vector<PointType> Vector;
    ...
    using Vector::at;
    using Vector::clear;
    using Vector::iterator;
    using Vector::const_iterator;
    using Vector::begin;
    using Vector::end;
    using Vector::cbegin;
    using Vector::cend;
    using Vector::crbegin;
    using Vector::crend;
    using Vector::empty;
    using Vector::size;
    using Vector::reserve;
    using Vector::operator[];
    using Vector::assign;
    using Vector::insert;
    using Vector::erase;
    using Vector::front;
    using Vector::back;
    using Vector::push_back;
    using Vector::pop_back;
    using Vector::resize;
    ...

In practical terms: If you do not have any data members in your derived class, you do not have any problems, not even in polymorphic usage. You only need a virtual destructor if the sizes of the base class and the derived class are different and/or you have virtual functions (which means a v-table).

BUT in theory: From [expr.delete] in the C++0x FCD: In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.

But you can derive privately from std::vector without problems.
I have used the following pattern:

class PointVector : private std::vector<PointType>
{
    typedef std::vector<PointType> Vector;
    ...
    using Vector::at;
    using Vector::clear;
    using Vector::iterator;
    using Vector::const_iterator;
    using Vector::begin;
    using Vector::end;
    using Vector::cbegin;
    using Vector::cend;
    using Vector::crbegin;
    using Vector::crend;
    using Vector::empty;
    using Vector::size;
    using Vector::reserve;
    using Vector::operator[];
    using Vector::assign;
    using Vector::insert;
    using Vector::erase;
    using Vector::front;
    using Vector::back;
    using Vector::push_back;
    using Vector::pop_back;
    using Vector::resize;
    ...
软的没边 2024-10-13 15:19:30

如果您遵循良好的 C++ 风格,则缺少虚函数不是问题,而是切片(请参阅https: //stackoverflow.com/a/14461532/877329

为什么缺少虚函数不是问题?因为函数不应该尝试删除它接收到的任何指针,因为它没有该指针的所有权。因此,如果遵循严格的所有权策略,则不需要虚拟析构函数。例如,这总是错误的(有或没有虚拟析构函数):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    delete obj;
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj); //Will crash here. But caller does not know that
//  ...
    }

相反,这总是有效(有或没有虚拟析构函数):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj);
//  The correct destructor *will* be called here.
    }

如果对象是由工厂创建的,工厂还应该返回一个指向工作删除器的指针,应该使用它来代替 delete,因为工厂可能使用自己的堆。调用者可以以 share_ptrunique_ptr 的形式获取它。简而言之,不要删除任何不是从new直接获得的内容。

If you follow good C++ style, the absence of virtual function is not the problem, but slicing (see https://stackoverflow.com/a/14461532/877329)

Why is absence of virtual functions not the problem? Because a function should not try to delete any pointer it receives, since it does not have an ownership of it. Therefore, if following strict ownership policies, virtual destructors should not be needed. For example, this is always wrong (with or without virtual destructor):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    delete obj;
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj); //Will crash here. But caller does not know that
//  ...
    }

In contrast, this will always work (with or without virtual destructor):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj);
//  The correct destructor *will* be called here.
    }

If the object is created by a factory, the factory should also return a pointer to a working deleter, which should be used instead of delete, since the factory may use its own heap. The caller can get it form of a share_ptr or unique_ptr. In short, do not delete anything you didn't get directly from new.

天生の放荡 2024-10-13 15:19:30

是的,只要您小心不做不安全的事情,它就是安全的...我认为我从未见过有人将向量与 new 一起使用,所以在实践中您可能会没事。然而,这不是 C++ 中的常见习惯用法......

您能提供有关算法的更多信息吗?

有时你最终会沿着一条设计路线走下去,然后看不到你可能采取的其他路径 - 你声称需要使用 10 种新算法进行矢量化这一事实给我敲响了警钟 - 真的有 10 种通用目的吗向量可以实现的算法,或者您是否正在尝试创建一个既是通用向量又包含应用程序特定功能的对象?

我当然不是说你不应该这样做,只是你提供的信息敲响了警钟,这让我认为你的抽象可能有问题,并且有更好的方法来实现你的目标想。

Yes it's safe as long as you are careful not to do the things that are not safe... I don't think I've ever seen anyone use a vector with new so in practice you'll likely be fine. However, it's not the common idiom in c++....

Are you able to give more information on what the algorithms are?

Sometimes you end up going down one road with a design and then can't see the other paths you might have taken - the fact that you claim to need to vector with 10 new algorithms rings alarm bells for me - are there really 10 general purpose algorithms that a vector can implement, or are you trying to make an object that is both a general purpose vector AND which contains application specific functions?

I'm certainly not saying that you shouldn't do this, it's just that with the information you've given alarm bells are ringing which makes me think that maybe something is wrong with your abstractions and there is a better way to achieve what you want.

不必在意 2024-10-13 15:19:30

我最近也继承了 std::vector ,发现它非常有用,到目前为止我还没有遇到任何问题。

我的类是一个稀疏矩阵类,这意味着我需要将矩阵元素存储在某个地方,即 std::vector 中。我继承的原因是我有点懒得为所有方法编写接口,而且我通过 SWIG 将类连接到 Python,其中已经有很好的 std::vector 接口代码。我发现将此接口代码扩展到我的类比从头开始编写新代码要容易得多。

我在该方法中看到的唯一问题并不是非虚拟析构函数,而是一些我想重载的其他方法,例如 push_back()resize ()insert() 等。私有继承确实是一个不错的选择。

谢谢!

I also inherited from std::vector recently, and found it to be very useful and so far I haven't experienced any problems with it.

My class is a sparse matrix class, meaning that I need to store my matrix elements somewhere, namely in an std::vector. My reason for inheriting was that I was a bit too lazy to write interfaces to all the methods and also I am interfacing the class to Python via SWIG, where there is already good interface code for std::vector. I found it much easier to extend this interface code to my class rather than writing a new one from scratch.

The only problem I can see with the approach is not so much with the non-virtual destructor, but rather some other methods, which I would like to overload, such as push_back(), resize(), insert() etc. Private inheritance could indeed be a good option.

Thanks!

时光瘦了 2024-10-13 15:19:30

这个问题肯定会产生令人窒息的珍珠般的紧握,但事实上,没有任何合理的理由来避免或“不必要地增加实体”来避免从标准容器中派生。最简单、最短的表达是最清晰、也是最好的。

您确实需要对任何派生类型进行所有通常的注意,但标准中的基数的情况没有什么特别的。重写基类成员函数可能很棘手,但对于任何非虚拟基类来说这都是不明智的,因此这里没有太多特别之处。如果要添加数据成员,如果该成员必须与基的内容保持一致,则需要担心切片,但这对于任何基都是相同的。

我发现从标准容器派生特别有用的地方是添加一个构造函数来精确执行所需的初始化,而不会出现混淆或被其他构造函数劫持。 (我正在看着你,initialization_list构造函数!)然后,你可以自由地使用生成的对象,切片——通过引用将其传递给需要基数的东西,从它移动到基数的实例,你有什么。无需担心边缘情况,除非将模板参数绑定到派生类会打扰您。

这项技术在 C++20 中立即有用的一个地方是预留。在我们可能已经写过的地方,

  std::vector<T> names; names.reserve(1000);

我们可以说

  template<typename C> 
  struct reserve_in : C { 
    reserve_in(std::size_t n) { this->reserve(n); }
  };

然后拥有,即使作为类成员

  . . .
  reserve_in<std::vector<T>> taken_names{1000};  // 1
  std::vector<T> given_names{reserve_in<std::vector<T>>{1000}}; // 2
  . . .

(根据偏好),并且不需要编写构造函数只是为了对它们调用reserve()。

(从技术上来说,reserve_in 需要等待 C++20 的原因是之前的标准不要求在移动过程中保留空向量的容量。这被认为是一个疏忽,可以合理地预期,该修复将在 20 年后及时修复,因为所有现有的实现实际上都没有保留跨移动的容量;急切的人可以安全地抢先——无论如何,保留几乎总是一种优化。)

有些人会认为,使用自由函数模板可以更好地满足 reserve_in 的情况:

  template<typename C> 
  auto reserve_in(std::size_t n) { C c; c.reserve(n); return c; }

这样的替代方案是当然可行——有时甚至可以无限快,因为 *RVO。但是派生或自由函数的选择应该根据其自身的优点进行,而不是出于对从标准组件派生的毫无根据的(呵呵!)迷信。在上面的示例中,只有第二种形式可以与 free 函数一起使用;尽管在类上下文之外,它可以写得更简洁一些:

  auto given_names{reserve_in<std::vector<T>>(1000)}; // 2

This question is guaranteed to produce breathless pearl-clutching, but in fact there is no defensible reason for avoiding, or "unnecessarily multiplying entities" to avoid, derivation from a Standard container. The simplest, shortest possible expression is clearest, and best.

You do need to exercise all the usual care around any derived type, but there is nothing special about the case of a base from the Standard. Overriding a base member function could be tricky, but that would be unwise to do with any non-virtual base, so there is not much special here. If you were to add a data member, you would need to worry about slicing if the member had to be kept consistent with contents of the base, but again that is the same for any base.

The place where I have found deriving from a standard container particularly useful is to add a single constructor that does precisely the initialization needed, with no chance of confusion or hijacking by other constructors. (I'm looking at you, initialization_list constructors!) Then, you can freely use the resulting object, sliced -- pass it by reference to something expecting the base, move from it to an instance of the base, what have you. There are no edge cases to worry about, unless it would bother you to bind a template argument to the derived class.

A place where this technique will be immediately useful in C++20 is reservation. Where we might have written

  std::vector<T> names; names.reserve(1000);

we can say

  template<typename C> 
  struct reserve_in : C { 
    reserve_in(std::size_t n) { this->reserve(n); }
  };

and then have, even as class members,

  . . .
  reserve_in<std::vector<T>> taken_names{1000};  // 1
  std::vector<T> given_names{reserve_in<std::vector<T>>{1000}}; // 2
  . . .

(according to preference) and not need to write a constructor just to call reserve() on them.

(The reason that reserve_in, technically, needs to wait for C++20 is that prior Standards don't require the capacity of an empty vector to be preserved across moves. That is acknowledged as an oversight, and can reasonably be expected to be fixed as a defect in time for '20. We can also expect the fix to be, effectively, backdated to previous Standards, because all existing implementations actually do preserve capacity across moves; the Standards just haven't required it. The eager can safely jump the gun -- reserving is almost always just an optimization anyway.)

Some would argue that the case of reserve_in is better served by a free function template:

  template<typename C> 
  auto reserve_in(std::size_t n) { C c; c.reserve(n); return c; }

Such an alternative is certainly viable -- and could even, at times, be infinitesimally faster, because of *RVO. But the choice of derivation or free function should be made on its own merits, and not from baseless (heh!) superstition about deriving from Standard components. In the example use above, only the second form would work with the free function; although outside of class context it could be written a little more concisely:

  auto given_names{reserve_in<std::vector<T>>(1000)}; // 2
秋日私语 2024-10-13 15:19:30

在这里,让我介绍另外两种方法来实现您想要的。一种是包装 std::vector 的另一种方法,另一种是继承而不给用户机会破坏任何东西的方法:

  1. 让我添加另一种包装 std::vector 的方法> 无需编写大量函数包装器。

#include <utility> // For std:: forward
struct Derived: protected std::vector<T> {
    // Anything...
    using underlying_t = std::vector<T>;

    auto* get_underlying() noexcept
    {
        return static_cast<underlying_t*>(this);
    }
    auto* get_underlying() const noexcept
    {
        return static_cast<underlying_t*>(this);
    }

    template <class Ret, class ...Args>
    auto apply_to_underlying_class(Ret (*underlying_t::member_f)(Args...), Args &&...args)
    {
        return (get_underlying()->*member_f)(std::forward<Args>(args)...);
    }
};
  1. 继承自 std::span 而不是 std::vector< /code> 并避免 dtor 问题。

Here, let me introduce 2 more ways to do want you want. One is another way to wrap std::vector, another is the way to inherit without giving users a chance to break anything:

  1. Let me add another way of wrapping std::vector without writing a lot of function wrappers.

#include <utility> // For std:: forward
struct Derived: protected std::vector<T> {
    // Anything...
    using underlying_t = std::vector<T>;

    auto* get_underlying() noexcept
    {
        return static_cast<underlying_t*>(this);
    }
    auto* get_underlying() const noexcept
    {
        return static_cast<underlying_t*>(this);
    }

    template <class Ret, class ...Args>
    auto apply_to_underlying_class(Ret (*underlying_t::member_f)(Args...), Args &&...args)
    {
        return (get_underlying()->*member_f)(std::forward<Args>(args)...);
    }
};
  1. Inheriting from std::span instead of std::vector and avoid the dtor problem.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文