2

方法があります

void foo(list<shared_ptr<Base>>& myList); 

これは、DerivedClass1とDerivedClass2の2種類のリストで呼び出そうとしています。

list<shared_ptr<DerivedClass1>> myList1; 
foo(myList1);
list<shared_ptr<DerivedClass2>> myList2; 
foo(myList2);

ただし、これは明らかにコンパイラエラーを生成します

error: a reference of type "std::list<boost::shared_ptr<Base>, std::allocator<boost::shared_ptr<Base>>> &" (not const-qualified) cannot be initialized with a value of type "std::list<boost::shared_ptr<DerivedClass1>, std::allocator<boost::shared_ptr<DerivedClass1>>>"

shared_ptrのコンテナをキャストする簡単な方法はありますか?これを達成できる代替コンテナの?

更新:回答してくれたすべての人に感謝します。言語の範囲内で作業する場合、メソッドを「現状のまま」維持しながら、shared_ptrのコンテナーを使用し、それを正確に渡す(呼び出しサイトで新しいリストを作成する)のが最善の方法のようです。

私はすでにこれを知っていると思いますが、shared_ptrのコンテナーを処理するBoostライブラリの他の部分について読んだことを思い出し、おそらく他の誰かによってもっとエレガントに解決されたのではないかと思いました。しかし、私自身のさらなる調査から、これらは、多数のポインターが排他的に所有されている場合のshared_ptrのオーバーヘッドの削減に向けられているようです(したがって、コンテナー内のオブジェクトごとに1つではなく、コンテナーごとに1つのロックが必要です)。

もう一度ありがとう、皆さんはすべて素晴らしいです!

4

4 に答える 4

7

fooSTL規則に従い、イテレータを使用するように変更します。

template< typename It >
void foo(It begin, It end); 

次に、イテレータをリストに渡します

list<shared_ptr<DerivedClass1>> myList1;
foo(myList1.begin(), myList1.end());
list<shared_ptr<DerivedClass2>> myList2;
foo(myList2.begin(), myList2.end());

そして、すべてがうまくいくはずです。

編集
これはスマートポインタにとって特別なことではないことに注意してください。から派生し場合でも、Astd::list<T1*>&をで初期化することはできません。std::list<T2*>T2T1

于 2010-05-06T15:14:10.373 に答える
4

あるタイプのコンテナを別のタイプのコンテナにキャストすることはできません。既存のコンテナによって格納されているオブジェクトのタイプが新しいコンテナによって格納されているオブジェクトのタイプに変換可能である場合、既存のコンテナから新しいコンテナを作成する方法はいくつかあります。

std::copy要素ごとの変換を行うために使用できます。

list<shared_ptr<Base> > baseList;
list<shared_ptr<Derived> > derivedList;
std::copy(derivedList.begin(), derivedList.end(), std::back_inserter(baseList));

baseList次の開始イテレータと終了イテレータを使用して直接構築することもできderivedListます。

list<shared_ptr<Base> > baseList(derivedList.begin(), derivedList.end());

関数が代わりにconst参照を取得できる場合は、関数呼び出しで一時的なものを作成できます。

typedef list<shared_ptr<Base> > BaseList;
foo(BaseList(derivedList.begin(), derivedList.end()));
于 2010-05-06T15:10:34.857 に答える
1

から継承した場合でも、list<shared_ptr<Base>>list<shared_ptr<DerivedClass1>>(または偶数 shared_ptr<Base>shared_ptr<DerivedClass1>)は完全に異なるタイプであることに注意してください。したがって、一方を他方にキャストすることは実際には間違っています。DerivedClass1Base

fooタイプの新しい要素をに追加しようとする場合を考えてみましょBasemyList。(たとえば、古いスタイルのCキャストを使用して)にキャストし、それをに渡すことmyList1ができた場合、結果は良くありません。list<shared_ptr<Base>>foo

したがって、私が見る唯一の適切な解決策は、新しいオブジェクトを作成し、他のリストの内容をそのオブジェクトにコピーしてから、@ James McNellisによって示されてlist<shared_ptr<Base>>いるように、それをに渡すことです。foo

于 2010-05-06T15:09:07.417 に答える
0

それが良い考えではない理由の古典的な説明は次のとおりです。

あなたがlist<Apple*>リンゴでうまく満たされていて、それを受け入れる関数にそれを渡すことができたなら、関数list<Fruit*>が新しいオレンジをリストに入れるのを止めることはできません。Alist<Fruit*>は単にaの代わりにはならずlist<Apple*>、関係はありません。

list<Apple*>との両方で機能する関数が必要な場合は、list<Orange*>テンプレートを使用できます(イテレーターを使用するか、コンテナー自体を取得するか、list<T*>-を完全に選択します。


本当にひどくaを渡すようにしたかったlist<Apple*>場合はlist<Fruit*>、型消去などを使用するコンテナ/イテレータのプロキシを作成することは技術的に可能であると思います-ポインタを内部でキャストしない/無効なキャストを停止する(オレンジをリンゴのリストに入れます)。これにより、代わりにlist_proxy<Fruit*>、派生型のリストを受け入れる関数を取得できます。

(ほんの始まり)の線に沿った何か:

#include <list>
#include <boost/shared_ptr.hpp>

template <class T>
class ListWrapperBaseAux
{
public:
    virtual ~ListWrapperBaseAux() {}
    virtual T* front() = 0;
};

template <class T, class U>
class ListWrapperAux: public ListWrapperBaseAux<T>
{
    std::list<U*>* list_ref;
public:
    ListWrapperAux(std::list<U*>* list_ref): list_ref(list_ref) {}
    virtual T* front() { return dynamic_cast<T*>(list_ref->front()); }
};

template <class T>
class ListProxy
{
    boost::shared_ptr<ListWrapperBaseAux<T> > list_ref;
public:
    template <class U>
    ListProxy(std::list<U*>& li): list_ref(new ListWrapperAux<T, U>(&li)) {}
    T* front() { return list_ref->front(); }
};

struct Fruit
{
    virtual ~Fruit() {}
};

struct Apple: Fruit {};
struct Orange: Fruit {};

void bake(ListProxy<Fruit> li)
{
    Fruit* f = li.front();
}

int main()
{
    std::list<Apple*> apples;
    bake(apples);

    std::list<Orange*> oranges;
    bake(oranges);
}
于 2010-05-06T15:55:49.493 に答える