如何在另一个向量中包含向量包装类时使用它?

时间:2015-05-12 09:41:14

标签: c++ vector wrapper stdvector

考虑来自第三方库的自由函数,该函数需要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向量矢量(编辑:并将元素添加到该向量):

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

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

有没有办法使用我的包装类型来调用bar() 我想做的是:

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

我想避免的一点是首先使用所需类型调用bar(),然后逐个将这些元素复制到我的vector<Wrapper>

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

Edit2 :举一个示例,请考虑以bar()根数据类型为int的以下玩具实现:

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

4 个答案:

答案 0 :(得分:3)

[需要在条形函数中添加元素的新评论后编辑] 一个可能的解决方案是保持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;
}

Example

答案 1 :(得分:1)

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

使用

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

无论如何,您可以将您的Wrapper对象插入vec

vec.push_back(a.data());

然后拨打bar(vec);

答案 2 :(得分:1)

开箱即用,调用带vector<vector<something>的函数将无法使用vector<Wrapper>,因为它们的类型不同,编译器明确地期望前者。

我认为这种形式的替换在C ++中没有任何作用。

解决方法

每个人都有一个解决方法:你可以在你自己的代码中使用转换来让魔法发生。

让我解释一下。

如果您打算使用的功能在{+ 1}}中使用C ++,那么基本上必须为其提供vector<vector<something>> 。因此,您无法将矢量设为vector<vector<something>>并避免将其转换为vector<Wrapper>

另一方面,你可以

  1. 使用vector<vector<something>>来推送vector<vector<something>的实例(使用隐式转化)。
  2. 如果您需要Wrapper功能,则可以使用转换构造函数转换Wrapper
  3. 让我们举个例子:

    vector<something>
      

    P.S。 #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(); } 函数将复制元素,因此如果您的函数确实修改了向量,它将不会反映在Wrapper上,因为它是已修改的内部向量的副本。使用真实的push_backvector<something>会产生相同的行为。

答案 3 :(得分:0)

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

假设使用以下玩具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;
}

还有一个问题:数据所有权。可能需要一些智能指针。

正在运行代码is here