【问题标题】:convert vector<boost::shared_ptr<Foo> > to vector<Foo*> , is it possible?将 vector<boost::shared_ptr<Foo> > 转换为 vector<Foo*> ,有可能吗?
【发布时间】:2012-11-27 01:46:05
【问题描述】:

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

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

我知道可以使用 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);

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

【问题讨论】:

  • 我认为更新应该去一个不同的问题,因为它是一个编译问题,如果你没有忘记在 cpp 中#include 标题,你的代码是正确的。我建议您使用 IDE,这是最简单的,但我现在正在研究它,如何正确编译和链接它。
  • 嗨,埃莱利亚斯!我刚刚找到了您的编译问题的答案:我的答案有点不准确,抱歉,我已经更正了。关键是您需要将显式模板实例化放入实现文件中,而不是头文件中。

标签: c++ boost shared-ptr


【解决方案1】:

shared_ptr&lt;T&gt;T* 是不同的类型,因此您不能简单地将vector&lt;shared_ptr&lt;T&gt;&gt; 转换为vector&lt;T*&gt;。如果您真的需要vector&lt;T*&gt;(这意味着您不能按照 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 的文档中未指定,因此硬编码可能不是一个好主意。要摆脱 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()));

当然,您可以改用 Boost.Iterators 中的 transform_iterator,但我发现使用 Range 会导致代码更具可读性。

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

【讨论】:

  • 感谢您的回答,您的回答中有很多我从未听说过或使用过的东西,所以我想我有一些学习要做。
  • @elelias:如前所述,我的第一个版本依赖于 C++11 的可读性,所以这并不令人惊讶。 c++03 版本应该看起来不那么陌生(但也不那么简洁),因为唯一奇怪的是Boost.Range(这是一个非常好的了解工具)
  • boost::copy_range&lt;std::vector&lt;T&gt;&gt;(foo),在文档中很容易混淆here
  • @LucDanton:谢谢,我不知道。我已经相应地更新了我的答案。
【解决方案2】:

如果你写了那个函数,我建议模板化,因为 shared_ptr 有operator*,就像你使用原始指针一样。

template<typename _Tp_ptr_Foo>
void your_fun(const vector<_Tp_ptr_Foo>& ); // or something alike here

在这种情况下,模板化与函数重载基本相同,但使用模板化可以避免重复代码。

如果您无法控制函数,则需要转换整个向量。如果它不超过 1000 个元素,并且您执行的次数不超过几百次,则无需担心太多的性能损失。

不幸的是,您不能将一个动态转换为另一个,因为它们不是通过继承相关的。虽然看起来很像,但vector&lt;T&gt;vector&lt;U&gt; 没有任何关系。

更新:
我同意 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 的评论)

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

// header file:

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

之后,您有两个选择:

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

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

【讨论】:

  • 感谢您的回答。理想情况下,我想保持对函数的现有调用保持不变。如果我将该函数提升为模板函数,我将不得不重新编写它并使用以下命令调用它: myFunc >( myVector_of_Foo ) 不是吗?
  • @elelias: 调用它为 myFunc(myVector_of_Foo) 应该可以工作(可以推导出模板类型)。
  • 您好,我正在实施您的解决方案,但出现了其他问题。我的函数需要几个指向 Foo 的指针向量。所以这意味着,如果我有 3 个参数 my_fun(vector1, vector2, vector3),并且每个参数都可以包含指针或共享指针,那么我必须编写六个声明才能使模板工作,不是吗? ?再次感谢。
  • 嗨!没问题,您不一定需要,请参阅我的更新答案。
  • 您好,很抱歉再次打扰您。我仍然遇到一些小问题,我已经相应地更新了问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
  • 2014-01-11
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 2019-10-20
相关资源
最近更新 更多