在不使用模板的情况下将多个大小的数组传递给虚拟方法

Passing multiple sized arrays to virtual method without using templates

本文关键字:数组 方法 虚拟 情况下      更新时间:2023-10-16

所以我有一个纯虚拟类,需要保持这种状态。在此类中,我有或技术上需要一个接受模板化参数的方法。下面是参数的对象类型:

template <int LENGTH>
struct MyStruct
{
  int arr[LENGTH];
};

这是我的方法:

template <int LENGTH>
virtual bool send_struct(const MyStruct<LENGTH>& mystruct) = 0;

但是,显然我不能将模板与虚拟类一起使用,另一种方法是将模板添加到类中,我也无法达到我的目的。在保持我的约束的同时,有没有其他选择?我需要在我的纯虚拟类中将不同大小的数组传递给此方法,但我无法模板化该类。

如你所知,你不能写这个:

template <int LENGTH>
virtual bool send_struct(const MyStruct<LENGTH>& mystruct) = 0;

无法通过编译时LENGTH。但是,您可以通过类型擦除容器来传递运行时长度:

virtual bool send_struct(gsl::span<int const> ) = 0;

gsl::span<T> 是一个非拥有的、连续的 T 容器。它是对数组或vector或其他任何东西的视图,也可以是MyStruct<N>。此类型不能直接从您的结构中构造,但很容易编写一个版本,或者将必要的成员添加到您的结构(.data().size())以使其工作。

一个非常简单的实现就是:

class my_span {
private:
    int const* begin_;
    int const* end_;
public:
    template <int L>
    my_span(MyStruct<L> const& ms)
        : begin_(ms.arr)
        , end_(ms.arr + L)
    { }
    int const* begin() const { return begin_; }
    int const* end() const { return end_; }
    int const* data() const { return begin_; }
    size_t size() const { return end_ - begin_; }
};

现在,对于一些不可修改的int容器,您有一个易于覆盖的virtual函数。

模板和虚拟方法相处得不好。您需要首先将MyStruct的模板化部分与类的其余部分隔离开来,并且仅使用虚拟方法处理非模板部分。其次,您需要抽象模板化部分以提供虚拟方法可以使用的非模板接口。对于数组,这很容易。您可以简单地提供指针和大小。要在表示形式之间进行转换,请添加一个中间非虚拟模板化方法,该方法调用实际的非模板虚拟方法。

struct MyStruct 
{
    // All non-templated members
};
template <int LENGTH>
struct MyStructArray : public MyStruct
{
    // All templated members
    int arr[LENGTH];
};

struct OtherStruct
{
    virtual bool send_struct_impl(const MyStruct& mystruct, const int * arr, int length) = 0;
    template <int LENGTH>
    bool send_struct(const MyStructArray<LENGTH>& mystruct)
    {
        return send_struct_impl(mystruct, mystruct.arr, LENGTH);
    }
};

或者,如果您不介意开销,则可以在 MyStruct 中存储指针和大小以供MyStructArray::arr。这将允许您在使用非模板引用或指向MyStruct的指针的每个上下文中使用arr

struct MyStruct 
{
protected:
    MyStruct(int * p_arr_ptr, int p_arr_length) :
        arr_ptr(p_arr_ptr), arr_length(p_arr_length) {}
public:
    int * arr_ptr;
    int arr_length;
    // All other members
};
template <int LENGTH>
struct MyStructArray : public MyStruct
{
    MyStructArray() : MyStruct(arr, LENGTH) {}
    int arr[LENGTH];
};

你可以让MyStruct<int>类型继承一个空的基类:

struct BaseStruct {};
template <int LENGTH>
struct MyStruct : BaseStruct 
{
  int arr[LENGTH];
};

并定义一个接受BaseStructlength的虚函数:

virtual bool send_struct(const BaseStruct& mystruct, int length) = 0;

最终,您可以提供一个方便的功能来从这些BaseStructlength转换为MyStruct<length>

template <int LENGTH>
const MyStruct<LENGTH>& to_mystruct(const BaseStruct& mystruct)
{
    return static_cast<const MyStruct<LENGTH>&>(mystruct);
}

关于科里鲁的演示