1

我有一个函数,它接受一个指向 Foo 的指针的 stl 向量作为参数。

但是,我也有对象是指向同一个类 Foo 的共享指针。我也希望能够调用这个函数来提供其他对象。我必须重载该功能吗?我似乎无法将其动态vector<shared_ptr<Foo>>转换为vector<Foo*>.

我知道可以使用 Get() 方法将 shared_ptr 转换为指针,但这又如何呢?有任何想法吗?

更新问题

我已经实现了下面建议的解决方案,但是现在,在为模板函数声明所有可能的类型时,我得到:

“'void my_func(std::vector&, std::vector&) [with 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);

我不明白这里有什么问题...

4

2 回答 2

4

shared_ptr<T>并且T*是不同的类型,因此您不能简单地从vector<shared_ptr<T>>to 转换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 代码的函子/functionptr 替换)并auto保存范围。IIRC 的文档中未指定范围转换的返回类型Boost.Range,因此硬编码可能不是一个好主意。要摆脱autoc++03 代码,您可以使用 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_iteratorfromBoost.Iterators代替,但我发现使用Range会导致更可读的代码。

当然,如果您将vector<Foo*>only 作为函数的参数,您可以跳过将其写入变量并直接调用myFunc(copy_range<std::vector<Foo*>>(...)),这可能会使编译器跳过几个副本。

于 2012-12-09T13:08:22.213 回答
3

如果您编写了该函数,我建议您使用模板化,因为 shared_ptroperator*就像您使用原始指针一样。

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)

唯一需要注意的是:如果您分别使用头文件和代码文件,则需要明确指示编译器应该创建两个函数,如下所示:

//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 的评论)

您的模板声明应如下所示:

// header file:

template<typename _Tp1, typename _Tp2, typename _Tp3>
void your_fun(const vector<_Tp1>&, const vector<_Tp2>&, const vector<_Tp3>& ); 

之后,您有 2 个选择:

  1. 您可以将定义放入单独的代码文件中。在这种情况下,您需要在头文件的实现文件中使用 6 个显式模板实例化,每个组合一个。

  2. 您可以将定义放入标题中,然后您不需要 6 个显式实例化。在这种情况下,我宁愿建议这样做。虽然它没有将声明和实现分开,但它并不是那么糟糕的解决方案。我也在严肃的 c++ 库中看到过这种方法,例如,您可以查看 OpenCV 中的 operations.hpp。

于 2012-12-09T12:58:41.667 回答