考虑来自第三方库的自由函数,该函数需要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);
}
答案 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;
}
答案 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>
。
另一方面,你可以
vector<vector<something>>
来推送vector<vector<something>
的实例(使用隐式转化)。Wrapper
功能,则可以使用转换构造函数转换Wrapper
。让我们举个例子:
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_back
和vector<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。