2

unique_ptrインスタンスを返す関数の関数ポインタを作成しようとしています。各関数は、多くの呼び出し元にとって一般的に役立つように、できるだけ具体的に型指定された値を返す必要があります (私の実際のコードでは、関数はコンストラクターと呼ばれ、各オブジェクトのパブリック ヘッダーにあります)。ただし、この特定の使用法では、各クラスが実装する一般的なインターフェイスだけを気にします。

unique_ptr<Subclass>を返す関数ポインタに返す関数を代入できないという問題が発生していますunique_ptr<Superclass>

例を次のスニペットに要約しました。

#include <iostream>
#include <memory>

struct Foo {
  virtual void foo() = 0;
};

struct Bar : public Foo {
  void foo() {};
};

std::unique_ptr<Foo>
foo_creator()
{
  return nullptr;
}

std::unique_ptr<Bar>
bar_creator()
{
  return nullptr;
}

typedef std::unique_ptr<Foo>(*creator_fn)();

int
main(int argc, char *argv[])
{
  std::unique_ptr<Foo> f;

  f = foo_creator();
  f = bar_creator();

  creator_fn foo_fn = foo_creator;
  creator_fn bar_fn = bar_creator; // Fails

  return 0;
}

clang ( Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)) から得られるコンパイル エラーは次のとおりです。

cannot initialize a variable of type 'creator_fn'
(aka 'std::unique_ptr<Foo> (*)()') with an lvalue
of type 'std::unique_ptr<Bar> ()':

different return type
('unique_ptr<struct Foo>' vs 'unique_ptr<struct Bar>')

私は、自分の目標を達成するためのより良い方法について言われることにもオープンです。:-)

4

2 に答える 2

2

このコードをコンパイルするために必要な機能は、型引数の共分散と呼ばれます。このテーマに関するウィキペディアの記事をご覧ください。

これが機能するためには、のサブタイプであるという事実は、それBarがのサブタイプであるFooことを意味する必要unique_ptr<struct Bar>がありますunique_ptr<struct Foo>

一部の言語にはこのプロパティがありますが、C ++にはないため、テンプレートと継承をうまく連携させることが難しくなります。Javaでは、次のように記述します。

UniquePtr<? extends Foo> f;
f = fooCreator();
f = barCreator();

WhereUniquePtr<? extends Foo> fは、型引数で共変である変数を宣言します。

なんらかの方法でこれを回避するデザインを見つける必要があると思います。この投稿には同様の質問が含まれているようで、いくつかの提案があります。

編集:私は質問を読み間違え、コンパイルエラーが間違った行にあると思ったので、上記の答えは少し誤解を招きます。私はまだ分散の欠如が問題だと思いますが、エラーはこの行で発生します:bar_fn = bar_creator; // Fails

于 2013-03-17T00:52:23.960 に答える
1

これは、特定の問題を解決するために使用した変更された設計です。新しい C++11 テンプレートusing宣言を使用して、返される特定の型をマークしました。関数を呼び出すと、問題なくアップキャストする機能を活用unique_ptrできます。

template <class T>
using creator_fn = std::unique_ptr<T>(*)();

int
main(int argc, char *argv[])
{
  std::unique_ptr<Foo> f;

  f = foo_creator();
  f = bar_creator();

  creator_fn<Foo> foo_fn = foo_creator;
  creator_fn<Bar> bar_fn = bar_creator;

  f = foo_fn();
  f = bar_fn();

  return 0;
}
于 2013-03-17T13:40:57.110 に答える