単純なクラスを考えてみましょう
template< typename T >
class Wrapper {
public:
// Constructors?
private:
T wrapped;
};
効果的にするには、どのコンストラクターを使用する必要がありますか?
C++0x より前は、次のいずれかを取るコンストラクターがありました。
- const 参照 (
T const&
) - タイプT
が「重い」場合、 - または値 (
T
) - タイプT
が「ライト」の場合。
T
タイプが「重い」か「軽い」かを判断するのは簡単ではありません。
組み込み型 (ints/floats/...) のみが「軽量」であると想定できます。しかし、それは完全に正しいとは言えません。なぜなら、私たち自身Wrapper<int>
も「軽い」タイプと見なされる可能性が最も高いからです。
ライブラリのようなboost::call_traits
ものは、型作成者が型を「軽量」としてマークできるようにすることで、この困難を克服する手段を提供します (適切なcall_traits
特殊化を提供することにより)。それ以外の場合は「重い」として扱われます。許容できるようです。
しかし、C++0x はそれをさらに悪化させます。T&&
これで、(いくつかの)「重い」オブジェクトを効率的に取得できる右辺値参照 ( ) もあるからです。
このため、次の中から選択する必要があります。
- const 参照 (
T const&
) のみ - タイプT
が「重い」で移動セマンティクスをサポートしていない場合 (大規模な POD のように移動セマンティクスが存在しないか、何も作成されておらず、それに影響を与えていないため)、 - const 参照 (
T const&
) と右辺値参照 ( )の両方T&&
- typeT
が「重い」で移動セマンティクスをサポートしている場合、 - 値 (
T
) のみ - タイプT
が「軽い」場合、または「重い」が移動セマンティクスをサポートしている場合 (コピーが作成されたとしても、それを使用する必要はありません。それ以外の場合は、T const&
とにかく自分自身からコピーする必要があります...)。
どのタイプが「重い」タイプで、どのタイプが「軽い」タイプかを見分けるのはまだ簡単ではありません (以前のように)。しかし今では、型T
が移動セマンティクスをサポートしているかどうかもわかりません (またはサポートしていますか?)。
可能なコンストラクターのオーバーロードの数が指数関数的に増加するため、複数の値をラップすると、これはさらに厄介になります。
その問題の解決策はありますか?
転送 (完全転送) 引数用のテンプレート コンストラクターについて調べましたが、それが期待どおりに機能するかどうかはわかりませんでした。T
また、コンストラクターに転送されるだけの異なる型の値を提供することもできます。これは機能と見なされる場合がありますが、そうである必要はありません。