私のヒントを参考にしてコーディングをしました前の質問の回答によると、Scene::addObject のオーバーロードに関する問題が発生しました。
関連する部分を繰り返し、可能な限り詳細を少なくしてこれを自己完結型にします。
- および
Interface
が含まれるを継承するオブジェクトの階層があります。Foo
Bar
Scene
これらのオブジェクトを所有する を所有しています。Foo
unique_ptr
私のメインでは、 はsになり、 は sBar
になりますshared_ptr
(前の質問で説明した理由によります)。- これら
main
はインスタンスに渡されScene
、インスタンスが所有権を取得します。
最小限のコード例はこれ:
#include <memory>
#include <utility>
class Interface
{
public:
virtual ~Interface() = 0;
};
inline Interface::~Interface() {}
class Foo : public Interface
{
};
class Bar : public Interface
{
};
class Scene
{
public:
void addObject(std::unique_ptr<Interface> obj);
// void addObject(std::shared_ptr<Interface> obj);
};
void Scene::addObject(std::unique_ptr<Interface> obj)
{
}
//void Scene::addObject(std::shared_ptr<Interface> obj)
//{
//}
int main(int argc, char** argv)
{
auto scn = std::make_unique<Scene>();
auto foo = std::make_unique<Foo>();
scn->addObject(std::move(foo));
// auto bar = std::make_shared<Bar>();
// scn->addObject(bar);
}
コメント行のコメントを解除すると、次のようになります。
error: call of overloaded 'addObject(std::remove_reference<std::unique_ptr<Foo, std::default_delete<Foo> >&>::type)' is ambiguous
scn->addObject(std::move(foo));
^
main.cpp:27:6: note: candidate: 'void Scene::addObject(std::unique_ptr<Interface>)'
void Scene::addObject(std::unique_ptr<Interface> obj)
^~~~~
main.cpp:31:6: note: candidate: 'void Scene::addObject(std::shared_ptr<Interface>)'
void Scene::addObject(std::shared_ptr<Interface> obj)
^~~~~
shared のコメントを外し、unique のコメントを外してもコンパイルされるので、問題はコンパイラが言うようにオーバーロードにあると解釈します。ただし、これらの型は両方とも何らかのコレクションに格納する必要があり、実際には base へのポインターとして保持されるため、オーバーロードが必要です (すべてshared_ptr
s に移動されている可能性があります)。
Scene
所有権を取得していること(および s の参照カウンタの増加)を明確にするため、両方を値渡ししていますshared_ptr
。問題がどこにあるのかまったくわかりませんし、他の場所でこの例を見つけることができませんでした。
ベストアンサー1
あなたが遭遇している問題は、このコンストラクタですshared_ptr
(13)(明示的ではない)は、同様の「基底への導出の移動」コンストラクタと同等によく一致します。unique_ptr
(6)(これも明示的ではありません)。
template< class Y, class Deleter >
shared_ptr( std::unique_ptr<Y,Deleter>&& r ); // (13)
13)
shared_ptr
によって現在管理されているオブジェクトを管理する を構築しますr
。 に関連付けられた削除子は、r
管理対象オブジェクトの将来の削除のために保存されます。はr
、呼び出し後にオブジェクトを管理しません。
std::unique_ptr<Y, Deleter>::pointer
が と互換性がない場合は、このオーバーロードはオーバーロード解決に参加しませんT*
。r.get()
がヌルポインターの場合、このオーバーロードはデフォルトコンストラクタ (1) と同等です。(C++17 以降)
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept; //(6)
6) 所有権を から に転送することで を構築します。
unique_ptr
ここで は指定された削除子 (E) を使用して構築されます。u
*this
u
このコンストラクターは、次の条件がすべて満たされる場合にのみオーバーロード解決に参加します。
a)
unique_ptr<U, E>::pointer
暗黙的にポインタに変換可能b)
U
配列型ではないc) は
Deleter
参照型であり、E
と同じ型であるかD
、または はDeleter
参照型ではなく、E
に暗黙的に変換可能である。D
非多態的なケースでは、非テンプレートムーブコンストラクタを使用するunique_ptr<T>
から を構築していますunique_ptr<T>&&
。オーバーロード解決では、非テンプレートが優先されます。
Scene
が sを格納していると仮定しますshared_ptr<Interface>
。その場合、 をオーバーロードする必要はなくaddObject
、unique_ptr
呼び出しで暗黙的な変換を許可するだけで済みます。