12

このような複数のコンストラクターを持つコピー不可能なクラスがあるとします

class Foo: boost::noncopyable
{
  public:
    Foo(std::string s) {...};  // construct one way        
    Foo(int i) {...};  // construct another way
 }

ここで、オブジェクトを作成し、実行時に使用するコンストラクターを選択します。

私はこのようなポインタでそれを行うことができます:-

boost::shared_ptr<Foo> f;

if (condition)
  f.reset(new Foo(myString));
else
  f.reset(new Foo(myInteger));

// common code follows
f->doSomethingComplicated(...);

しかし、それは面倒で遅いと感じます。動的割り当てに頼らずにオブジェクトのコンストラクターを選択する簡単な方法はありますか?


詳細: 上記のFooクラスは単に問題を説明するためのものです。実際に関係するクラスは Windows ですGdiplus::Bitmap- http://msdn.microsoft.com/en-gb/library/windows/desktop/ms534420(v=vs.85)。 aspx

4

6 に答える 6

2

スタック上の C++ 11 を使用して、新しい配置を使用せず、コピー/移動コンストラクター/割り当てを使用せずに実行できます。観察:

auto factory = [&]() -> Foo 
{ 
  if (condition) {
    return { myString };
  } else {
    return { myInteger };
  }
};
Foo&& foo = factory();
foo.doSomethingComplicated();

functor と Foo インスタンスはスタック上で問題なく動作し、割り当ては行われません (Fooおそらく のコンストラクターでの文字列のコピーを除く)。Foo は、スコープ外になるとデストラクタが呼び出されます。勝つ。

均一な初期化を使用して戻り値を作成する場合、コピー/移動操作は含まれません。返すmyString(暗黙の変換) または、そのようなコピー/移動を省略できる場合でもFoo(myString)、オブジェクトがコピー可能/移動可能かどうかをコンパイラに強制的にチェックさせることに注意してください。

編集:代わりに、これをさらに短くすることもできますが、もう少し「魔法」にします:

Foo&& foo = [&]() -> Foo 
{ 
  if (condition) {
    return { myString };
  } else {
    return { myInteger };
  }
}();

編集: Pre-C++11、Visual Studio ハック ソリューション:

関数から値を返すために暗黙的な変換コンストラクターを使用する場合、VC はオブジェクトがコピー可能かどうかをチェックしていないようです。したがって、標準に反していますが、これは有効です。

Foo make_foo(bool condition, const std::string&s, int i)
{
    if ( condition) {
        return s;
    } else {
        return i;
    }
}

次に、次のように使用します。

Foo& f = make_foo(condition, myString, myInteger);

これは別の VC ハックであることに注意してください。標準によれば、可変オブジェクトへの参照に一時を割り当てることはできません。つまり、変更する必要があるためconst Foo&、ここではかなり制限されます。

このように処理する必要があるとは言いませんが、可能です。

于 2014-05-29T13:39:47.780 に答える
1

あなたのデザインには欠陥があります。「Foo」は、型省略をクラスのユーザーに委譲しています。boost::any を見てください ( http://www.boost.org/doc/libs/1_55_0/doc/html/any.html )

于 2014-05-29T12:23:39.040 に答える
0

小さくてシンプルにしてください。これが非常に局所的な問題である場合は、電話を繰り返してみませんか?

if (condition)
{
  Foo f(myString);
  f.doSomethingComplicated();
}
else
{
  Foo f(myInt);
  f.doSomethingComplicated();
}

それが実現できない場合は、Fooポインター (またはスマート ポインター) を新しいクラスでラップします。

class FooWrapper // copyable
{
private:
    boost::shared_ptr<Foo> m_foo;
public:
    FooWrapper(std::string const &s) : m_foo(new Foo(s)) {}
    FooWrapper(int i) : m_foo(new Foo(i)) {}
    void doSomethingComplicated() { m_foo->doSomethingComplicated(); }
};

FooWrapper foo = condition ? FooWrapper(myString) : FooWrapper(myInt);
foo.doSomethingComplicated();
于 2014-05-29T13:01:23.063 に答える