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はJet*ではなくshared_ptrです。

.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>とは異なる型であるため、単純に fromから にT*キャストすることはできません。本当に必要な場合(Barnabas Szabolcs の回答に従って関数を変更できないことを意味します)、ソース ベクターからポインターを手動でコピーする必要があります。とにかくブーストを使用しているので、使用しても問題ないと思います。C++11 を使用できる場合、これは非常に簡単に実行できます。vector<shared_ptr<T>>vector<T*>vector<T*>Boost.Range

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++03 コードの functor/functionptr に簡単に置き換えることができます) に C++11 を使用し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_iteratorfromを使用することもできますが、使用するとより読みやすいコードになることがわかりました。Boost.IteratorsRange

もちろんvector<Foo*>、関数への引数として your only を使用する場合は、変数への書き込みをスキップして直接呼び出すことができますmyFunc(copy_range<std::vector<Foo*>>(...))。これにより、コンパイラはいくつかのコピーをスキップできる可能性があります。

于 2012-12-09T13:08:22.213 に答える
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)

注意する必要がある唯一のこと:ヘッダーファイルとコードファイルを別々に操作する場合は、次のように、両方の関数を作成するようにコンパイラーに明示的に指示する必要があります。

//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 :(エレリアスのコメントに答える)

テンプレート宣言は次のようになります。

// header file:

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

その後、2つのオプションがあります。

  1. 定義を別のコードファイルに入れることができます。その場合、ヘッダーの実装ファイルに、組み合わせごとに1つずつ、合計6つの明示的なテンプレートのインスタンス化が必要になります。

  2. 定義をヘッダーに入れることができ、6つの明示的なインスタンス化は必要ありません。この場合、私はむしろこれを提案したいと思います。宣言と実装を分離していませんが、それほど悪い解決策ではありません。私はこのアプローチを深刻なC++ライブラリでも見ました。例として、OpenCVのoperations.hppを見ることができます。

于 2012-12-09T12:58:41.667 に答える