我有一个函数,它接受一个指向Foo的stl向量作为参数。
但是,我也有对象是同一个类Foo的共享指针。我希望能够调用此函数来提供其他对象。我是否必须重载该功能?我似乎无法将其从vector<shared_ptr<Foo>>
动态投射到vector<Foo*>
。
我知道可以使用Get()方法将shared_ptr转换为指针,但是这个呢?有什么想法吗?
更新问题:
我已经实现了下面建议的解决方案,但现在,在声明模板函数的所有可能类型时,我得到:
“void my_func(std :: vector&amp;,std :: vector&amp;)的显式实例化[与Ptr_Jet1 = Jet *,Ptr_Jet2 = Jet *]'但没有定义”
和所有其他组合相同(例如,Ptr_Jet1是shared_ptr而不是Jet *。
在.cpp文件中,我有:
template<typename Ptr_Jet1, typename Ptr_Jet2>
void my_func(vector<Ptr_Jet1> vec1, vector<Ptr_Jet2> vec2){
//definition
}
在.h文件中,我有:
typedef boost::shared_ptr<Jet> ptr_jet;
template<typename Ptr_Jet1, typename Ptr_Jet2>
void my_func(vector<Ptr_Jet1> vec1, vector<Ptr_Jet2> vec2);
//
template void my_func(vector<Jet*> vec1, vector<Jet*> vec2);
template void my_func(vector<Jet*> vec1, vector<ptr_jet> vec2);
template void my_func(vector<ptr_jet> vec1, vector<Jet*> vec2);
template void my_func(vector<ptr_jet> vec1, vector<ptr_jet> vec2);
我不明白这里有什么不对......
答案 0 :(得分:4)
shared_ptr<T>
和T*
是不同的类型,因此您不能简单地从vector<shared_ptr<T>>
投射到vector<T*>
。如果你确实需要一个vector<T*>
(意思是根据Barnabas Szabolcs的答案你无法改变你的功能),你需要手动将指针复制出源向量。既然你正在使用boost,我认为使用Boost.Range
是可以的。如果你可以使用C ++ 11,这很简单:
vector< shared_ptr<Foo> > foo;
auto range = foo | boost::adaptors::transform([](shared_ptr<Foo>& ptr) { return ptr.get(); };
std::vector<Foo*> bar(range.begin(), range.end());
这使用C ++ 11作为lambda函数(可以很容易地用c ++ 03代码的functor / functionptr替换)和auto
来保存范围。 IIRC Boost.Range
的文档中未指定范围转换的返回类型,因此对其进行硬编码可能是一个坏主意。要删除c ++ 03代码中的auto
,可以使用boost::copy_range
:
struct transformation //using a functor instead of a plain function will enable inlining of the transformation, which is liekly benefitial for performance
{ Foo* operator()(shared_ptr<Foo>& ptr) { return ptr.get();}};
std::vector<Foo*> bar = boost::copy_range<std::vector<Foo*>>(foo | boost::adaptors::transform(transformation()));
当然,您可以使用transform_iterator
中的Boost.Iterators
,但我发现使用Range
可以获得更易读的代码。
当然,如果您仅将vector<Foo*>
用作函数的参数,则可以跳过将其写入变量并直接调用myFunc(copy_range<std::vector<Foo*>>(...))
,这可能会使编译器跳过几个副本
答案 1 :(得分:3)
如果您编写了该函数,我建议使用模板化,因为shared_ptr有operator*
,就像使用原始指针一样。
template<typename _Tp_ptr_Foo>
void your_fun(const vector<_Tp_ptr_Foo>& ); // or something alike here
在这种情况下,模板化与函数重载基本相同,但是通过模板化可以避免重复代码。
如果您无法控制该功能,则需要转换整个矢量。如果它不超过1000个元素并且你不会超过几百次,那么恐怕没有太多的性能损失。
不幸的是,你不能将它们动态地转换为另一个,因为它们与继承无关。虽然它们看起来很相似,但vector<T>
与vector<U>
无关。
更新:
我同意Grizzly,模板参数会自动推断出来,所以你不需要明确地写出来。所以你可以继续称它为your_fun(v)
。
您唯一需要注意的事项是:如果您单独处理标题和代码文件,则需要explicitly instruct the compiler that it should create both of your functions,如下所示:
//header file:
template<typename _Tp_ptr_Foo>
void your_fun(const vector<_Tp_ptr_Foo>& );
template void your_fun(const vector<Foo*>& );
template void your_fun(const vector<shared_ptr<Foo> >& );
//code file:
template<typename _Tp_ptr_Foo>
void your_fun(const vector<_Tp_ptr_Foo>& )
{
// implementation
}
UPDATE2 :(回答Elelias'es评论)
您的模板声明应如下所示:
// header file:
template<typename _Tp1, typename _Tp2, typename _Tp3>
void your_fun(const vector<_Tp1>&, const vector<_Tp2>&, const vector<_Tp3>& );
之后,您有两个选择:
您可以将定义放入单独的代码文件中。在这种情况下,您需要在标题的实施文件中有6个显式模板实例化,每个组合一个。
您可以将定义放入标题,然后您不需要6个显式实例化。在这种情况下,我宁愿建议这样做。虽然它没有单独声明和实现,但它并不是那么糟糕的解决方案。我也在严肃的c ++库中看到过这种方法,作为一个例子,你可以看看OpenCV中的operations.hpp。