4

ノート:

liveworkspace.orgによると、この質問への答えは、g ++(4.7.2)、clang(3.2)、およびicc(13.0.1)の最近のバージョンで機能しますが、Stephen Linの発言によると、空のベースの最適化との実装std::tuple


元の質問:

次のようなテンプレート構造体がある場合:

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2
>
struct ComboThree {
    T1 data_1[N1];
    T2 data_2[N2];
};

特殊化することで、長さゼロの配列と余分な配置パディングを回避できます。

template<class T1, class T2>
struct ComboThree<T1, 0, T2, 0> {
};

template<class T1, class T2, unsigned short N2>
struct ComboThree<T1, 0, T2, N2>
{
    T2 data_2[N2];
};

template<class T1, unsigned short N1, class T2>
struct ComboThree<T1, N1, T2, 0>
{
    T1 data_1[N1];
};

しかし、TX / NXペアのXがはるかに大きくなると、このように専門化するのは面倒になります。私のプロジェクトでは、実際のさまざまな組み合わせの数はおそらく5つ未満になるため、テンプレートをまったく使用しないことになりますが、興味がありました。

TEMPLATE MAGICを使用して、余分なスペースを占有しないようにしながら、長さがゼロの配列を回避する方法はありますか?

たとえば、これは次のとおりです。

template<class T, unsigned short N>
struct Array {
    T data[N];
};

template<class T>
struct Array<T, 0> {};

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2
>
struct ComboTwo {
    Array<T1, N1> data_1;
    Array<T2, N2> data_2;
};

長さゼロの配列を回避しますが、空の構造体は余分なスペースを占有します。一方、これは:

template<class T, unsigned short N>
struct Array {
    T data[N];
};

template<class T>
struct Array<T, 0> {};

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2
>
struct ComboFour : Array<T1, N1>, Array<T2, N2> {};

私がやりたいことをしているようですが(そうですか?)、プログラムのArray<>基本構造体のデータにアクセスする方法がわかりません。 また、以下のStephenLinが指摘する他の制限もあります。

4

1 に答える 1

2

これは完全な答えではありませんが、コメントに収めるのは難しすぎます。のサブオブジェクトにアクセスするにはComboFour、本当に最後のオプションを実行したい場合は、次の醜い構文が必要になります。

ComboFour<int, 2, float, 1> cf;
cf.Array<int, 2>::data[0] = 0;
cf.Array<int, 2>::data[1] = 1;
cf.Array<float, 1>::data[0] = 2.0f;

おそらくいくつかのアクセサ関数でこれをクリーンアップすることができますが、それでも素晴らしいことではありません。

ただし、より大きな問題は、以下がエラーであるということです。

ComboFour<int, 1, int, 1> cf2 // fails to compile

同じクラスを親として2回使用することはできないためです。

(また、のArray<T, 0>サブオブジェクトはComboFourゼロスペースを取る場合と取らない場合があります。これは「空のベース最適化」と呼ばれ、標準では許可されていますが、必須ではありません。)

2番目の問題を回避する方法はおそらくいくつかあります...の継承std::tuple<...>(標準ライブラリの実装によって内部的に空のベース最適化を使用して実装される場合とされない場合があります)はArray<T, N>、おそらくこれを行う最も簡単な方法だと思います。本当にそうしなければなりませんでしたが、それは構文をさらに醜くします。

編集:これはGCC4.7.2で動作します

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2,
    class T3, unsigned short N3
>
struct Combo : std::tuple<Array<T1, N1>, Array<T2, N2>, Array<T3, N3>>
{
};

以降...

Combo<int, 2, int, 2, float, 3> c;
std::get<0>(c).data[0] = 0;
std::get<0>(c).data[1] = 1;
std::get<1>(c).data[0] = 2;
std::get<1>(c).data[1] = 3;
std::get<2>(c).data[0] = 0.0;
std::get<2>(c).data[1] = 1.0;
std::get<2>(c).data[2] = 2.0;

assert(sizeof(Combo<int, 0, int, 0, float, 1>) == sizeof(float));

(正直なところ、標準ライブラリを使用するには、多かれ少なかれ空のベースの最適化が必要です。したがって、必須ではありませんが、最近のコンパイラがそれをサポートしていなかった場合は驚きます。std::tuple<...>これを適切に利用するように記述されているかどうかは関係ありません。最適化は別の問題です。)

于 2013-03-03T07:14:22.973 に答える