当包含在另一个向量中时,如何使用矢量包装程序类

How can I use a vector wrapper class when enclosed in another vector?

本文关键字:何使用 包装 程序 包含 另一个 向量      更新时间:2023-10-16

考虑从第三部分库中的免费功能,该库期望std::vector作为参数:void foo( std::vector<sometype>& );

现在,我围绕此类型编写包装器,以便可以添加成员功能。为了能够将foo()与该类型一起使用,我添加了一个访问功能。

class Wrapper
{
   private:
      std::vector<sometype> _data;
   public:
       std::vector<sometype>& data() { return _data; }
       const std::vector<sometype>& data() const { return _data; }
       //... other stuff
};

这样,我仍然可以使用foo()

Wrapper a;
foo( a.data() );

但是现在考虑另一个功能,它期望sometype的向量向量( edit:它将元素添加到该矢量):

void bar( std::vector<std::vector<sometype>>& );

但是我拥有的数据类型是std::vector<Wrapper> vec;

是否有任何方法可以使用我的包装器类型来调用bar()我想做的是:

 std::vector<Wrapper> vec;
 bar( ??? );

我要避免的点是首先使用所需类型的bar(),然后必须一个一个一个一个一个将元素复制到我的vector<Wrapper>中。

起初,我会说"不",但也许有一些明智的解决方案?

edit2 :要举一个示例,请使用int的CC_11 root DataType考虑以下玩具实现:

void bar( std::vector<std::vector<int>>& vv )
{
   std::vector<int> v1 = { 1,2,3 };
   std::vector<int> v2 = { 4,5,6 };
   vv.push_back(v1);
   vv.push_back(v2);
}

[在需要在bar函数中添加元素的新注释后编辑] 一种可能的解决方案是保留std::vector<std::vector<sometype>>以供使用函数,并仅在VectorAccessor对象上操作引用

#include <iostream>
#include <vector>
struct sometype {
    int value;
    sometype(int v) : value(v) {}
};
void bar(std::vector<std::vector<sometype>>& par) {
    std::cout << "bar() - Before adding new elements:" << std::endl;
    for (auto& subvec : par) {
        std::cout << "Subvector: {";
        for (auto& sometypeItem : subvec) {
            std::cout << sometypeItem.value << " ";
        }
        std::cout << "};" << std::endl;
    }
    std::vector<sometype> newItem = {32, 33};
    par.emplace_back(newItem);
}
class VectorAccessor {
    std::vector<std::vector<sometype>>& m_vec;
public:
    VectorAccessor(std::vector<std::vector<sometype>>& v) : m_vec(v) {}
    template<typename V>
    void addVector(V&& vec) {
        static_assert(std::is_same<typename std::remove_reference<V>::type, 
            std::vector<sometype>>::value, "Not the right type");
        m_vec.emplace_back(std::forward<V>(vec));
    }
    std::vector<sometype> accessVector(size_t index) {
        return m_vec[index];
    }
};
int main(int argc, char ** argv)
{
    std::vector<std::vector<sometype>> vec;
    VectorAccessor vAcc(vec);

    // Add an element through the vector accessor
    std::vector<sometype> firstVector = {42};
    firstVector.emplace_back(52);
    vAcc.addVector(firstVector);
    // Call bar and add a few elements
    bar(vec);
    // Now access stuff with the usual wrapper
    std::cout << "Elements added by bar:" << std::endl;
    std::cout << "Subvector: {";
    for (auto& sometypeItem : vAcc.accessVector(1)) {
        std::cout << sometypeItem.value << " ";
    }
    std::cout << "};" << std::endl;
    return 0;
}

示例

开箱即用,呼叫 vector<vector<something>的函数无法使用vector<Wrapper>,因为它们的类型是不同的,并且编译器明确期望前者。

我认为这种类型替代的任何方式都无法在C 中起作用。

解决方案

每个人都有解决方法:您可以使用自己的代码中的转换使魔术发生。

让我解释。

如果您打算使用的功能以vector<vector<something>>为CC ,则您基本上必须给它一个vector<vector<something>> 。因此,您不能将矢量作为vector<Wrapper>创建,并避免将其转换为vector<vector<something>>

另一方面,您可以

  1. 使用vector<vector<something>,您将在其中推动Wrapper的实例(使用隐式转换)。
  2. 如果您需要Wrapper函数性,则可以使用转换构造函数转换vector<something>

让我们以这个例子:

#include <iostream>
#include <vector>
using namespace std;
//Templated class wrapper. It does not have to be templated though.
template<typename T>
class Wrapper{
private:
    
    //Here is our inner vector.
    vector<T> vect;
public:
    //here is our implicit convertion operator : 
    operator vector<T>& () const {return this->vect;} 
    //A function so that we can push some stuff in it
    void push(T elem){
        this->vect.push_back(elem);
    }
   
    //here is some additional functionnality in top of vector;
    void print(){
        int i = 0;
        for(i=0;i<this->vect.size();i++){
            cout << vect[i] << " ";
        }
        cout << endl;
    }
    //this is our very simple conversion constructor
    Wrapper<T>(vector<T> vect){
        this->vect = vect;
    }
    //we still need a normal constructor
    Wrapper<T>(){}
};
//A function that takes a vector of vectors.
vector<int> concat(vector<vector<int>> vectors){
    int i = 0,j=0;
    vector<int> result;
    for(i=0;i<vectors.size();i++){
        for(j=0;j<vectors[i].size();j++){
            result.push_back(vectors[i][j]);
        }
    }
    return result;
}
int main()
{
    //Let's create an instance of Wrapper and fill it.
    Wrapper<int>ex;
    ex.push(1);
    ex.push(2);
    //And yet another one
    Wrapper<int>ex2;
    ex2.push(5);
    ex2.push(6);
    //Here we create precisely what the 'concat' function wants:
    //namely a vector<vector<int>>.
    vector<vector<int>> vectors;
    //you can push Wrappers in it, since the conversion will take place.
    vectors.push_back(ex);
    vectors.push_back(ex2);
    //this function call will be successful, since the type of
    //vectors is vector<vector<int>>
    vector<int> res = concat(vectors);
    //Now if you want to use the wrapper functionnality on any
    //vector<int>, just convert it on-demand.
    //The constructor is extra light-weight in terms of computing power
    //as you can see above.
    Wrapper<int>(res).print();
    Wrapper<int>(vectors[0]).print();
}

P.S。push_back功能将复制该元素,因此,如果您的函数确实修改了您的向量,则不会在包装器上反映它,因为它是已修改的内部向量的副本。使用真实的vector<something>push_back会导致相同的行为。

而不是 std::vector<Wrapper> vec;

使用

std::vector< std::vector<sometype> > vec;

无论如何,您可以将包装器对象插入VEC

vec.push_back(a.data());

,然后致电bar(vec);

好的,所以我想出了一些似乎有效的东西,尽管可能还有一些问题。这个想法是将向量的向量包装到某些全局包装器中,然后使用指针访问其内部数据的初始包装器。

用以下玩具bar()函数说:

void bar(std::vector<std::vector<int>>& par)
{
   std::vector<int> v1 = { 1,2,3 };
   par.push_back(v1);
}

两个包装纸:

struct GlobalWrapper
{
    std::vector<std::vector<int>> _data;
    size_t size() const { return _data.size(); }
    std::vector<int>& Get( size_t i ) { return _data[i]; }
    const std::vector<int>& Get( size_t i ) const { return _data[i]; }
};
struct Wrapper
{
    std::vector<int>* _data;
    void DoSomething() const
    {
        cout << "values: "; 
        std::copy( _data->begin(), _data->end(), std::ostream_iterator<int>(std::cout, " "));        
    }
    Wrapper( std::vector<int>& value ) : _data(&value)
    {
    }
};

和一个测试程序:

int main(int argc, char ** argv)
{
    GlobalWrapper gw;
    cout << "size before=" << gw.size() << endl;
    bar( gw._data );
    cout << "size after=" << gw.size() << endl;
    Wrapper w = gw.Get(0); // get first element and do something with it
    w.DoSomething();
    return 0;
}

剩下的一个问题:数据所有权。可能需要一些明智的指针。

运行代码在这里。