4

単純なクラスを考えてみましょう

template< typename T >
class Wrapper {
public:
  // Constructors?
private:
  T wrapped;
};

効果的にするには、どのコンストラクターを使用する必要がありますか?


C++0x より前は、次のいずれかを取るコンストラクターがありました。

  1. const 参照 ( T const&) - タイプTが「重い」場合、
  2. または値 ( T) - タイプTが「ライト」の場合。

Tタイプが「重い」か「軽い」かを判断するのは簡単ではありません。

組み込み型 (ints/floats/...) のみが「軽量」であると想定できます。しかし、それは完全に正しいとは言えません。なぜなら、私たち自身Wrapper<int>も「軽い」タイプと見なされる可能性が最も高いからです。

ライブラリのようなboost::call_traitsものは、型作成者が型を「軽量」としてマークできるようにすることで、この困難を克服する手段を提供します (適切なcall_traits特殊化を提供することにより)。それ以外の場合は「重い」として扱われます。許容できるようです。


しかし、C++0x はそれをさらに悪化させます。T&&これで、(いくつかの)「重い」オブジェクトを効率的に取得できる右辺値参照 ( ) もあるからです。

このため、次の中から選択する必要があります。

  1. const 参照 ( T const&) のみ - タイプTが「重い」で移動セマンティクスをサポートしていない場合 (大規模な POD のように移動セマンティクスが存在しないか、何も作成されておらず、それに影響を与えていないため)、
  2. const 参照 ( T const&) と右辺値参照 ( )の両方T&&- typeTが「重い」で移動セマンティクスをサポートしている場合、
  3. 値 ( T) のみ - タイプTが「軽い」場合、または「重い」が移動セマンティクスをサポートしている場合 (コピーが作成されたとしても、それを使用する必要はありません。それ以外の場合は、T const&とにかく自分自身からコピーする必要があります...)。

どのタイプが「重い」タイプで、どのタイプが「軽い」タイプかを見分けるのはまだ簡単ではありません (以前のように)。しかし今では、型Tが移動セマンティクスをサポートしているかどうかもわかりません (またはサポートしていますか?)。


可能なコンストラクターのオーバーロードの数が指数関数的に増加するため、複数の値をラップすると、これはさらに厄介になります。

その問題の解決策はありますか?

転送 (完全転送) 引数用のテンプレート コンストラクターについて調べましたが、それが期待どおりに機能するかどうかはわかりませんでした。Tまた、コンストラクターに転送されるだけの異なる型の値を提供することもできます。これは機能と見なされる場合がありますが、そうである必要はありません。

4

2 に答える 2

7

それどころか、C++11 ではユニバーサル参照のおかげで簡単になります。

template <typename T> struct Wrapper
{
    T value;

    template <typename U> Wrapper(U && u)
    : value(std::forward<U>(u))
    {  }
};

Tさらにいい感じに、が から構築可能である場合にのみ存在するデフォルトの 2 番目の引数を追加しUて、クラス自体が一致しない型から構築可能に見えないようにする必要があります。そして、それも可変長にします:

template <typename ...Args>
Wrapper(Args &&... args,
        typename std::enable_if<std::is_constructible<T, Args...>::value, int>::type = 0)
: value(std::forward<Args>(args)...)
{  }

#include <utility>forforward#include <type_traits>for traitsを確認してください。

于 2012-07-20T11:26:52.367 に答える
3

とにかくコピーする場合はT、パラメーターを値で渡し、コンパイラーにコピーを理解させる方がよい場合があります。何をするにしても、とにかく少なくとも 1 つのコピーが存在することになります。

template< typename T >
class Wrapper {
public:
  Wrapper(T value) : wrapped(std::move(value))
  { }
private:
  T wrapped;
};

速度が必要ですか?を参照してください。Dave Abrahamsによる値渡し。

于 2012-07-20T12:46:17.357 に答える