13

私はそれが行われたのを見たことがあると確信しているので、これが可能であると確信しています。素晴らしいと思いますが、「これはひどいアイデアです。なぜなら____だから」というような回答を喜んで受け入れます。

基本的な構造体があるとします。

struct vertex
{
    float x, y, z;
};

ここで、これらの変数にエイリアスを実装したいと思います。

vertex pos;
vertex col;
vertex arr;

pos.x = 0.0f; pos.y = 0.5f; pos.z = 1.0f;
col.r = 0.0f; col.g = 0.5f; col.b = 1.0f;
arr[0] = 0.0f; arr[1] = 0.5f; arr[2] = 1.0f;

理想的には、3 番目の構文は配列と見分けがつかないものです。つまり、arrデータを格納する float の配列を期待する関数 (たとえば、OpenGLglGet関数の多く) に参照パラメーターとして送信した場合、正常に動作します。

どう思いますか?可能?可能ですが、愚かですか?

4

13 に答える 13

24

私がすることは、アクセサーを作成することです:

struct Vertex {
    float& r() { return values[0]; }
    float& g() { return values[1]; }
    float& b() { return values[2]; }

    float& x() { return values[0]; }
    float& y() { return values[1]; }
    float& z() { return values[2]; }

    float  operator [] (unsigned i) const { return this->values_[i]; }
    float& operator [] (unsigned i)       { return this->values_[i]; }
    operator float*() const { return this->values_; }

private:
    float[3] values_;
}
于 2009-01-30T06:12:45.947 に答える
14

ユニオン内の名前のないネストされた構造体は、標準の C++ ではありません。ただし、これは機能するはずです。

struct Vertex
{
private:
   typedef float Vertex::* const vert[3];
   static const vert v;

public:
   typedef size_t size_type;
   float x, y, z;

   const float& operator[](size_type i) const {
      return this->*v[i];
   }

   float& operator[](size_type i) {
      return this->*v[i];
   }

};

const Vertex::vert Vertex::v = {&Vertex::x, &Vertex::y, &Vertex::z};

編集:もう少し情報。構造体は、オーバーロードされた [] 演算子のデータにアクセスするために、データ メンバーへの 3 つのポインターの配列を使用します。

「typedef float Vertex::* const vert」という行は、vert が Vertex 構造体の float メンバーへのポインターであることを意味します。[3] は、これらの 3 つの配列であることを意味します。オーバーロードされた operator[] では、この配列にインデックスが付けられ、データ メンバーへのポインターが逆参照され、値が返されます。

さらに、このメソッドは、パッキングの問題に関係なく機能するはずです。コンパイラは Vertex 構造体を自由にパディングできますが、それでも問題なく機能します。フロートが異なる方法でパックされている場合、無名共用体は問題に遭遇します。

于 2009-01-30T07:12:23.283 に答える
14

ユニオンを使用しますか?

union vertex
{
    struct { float x, y, z; };
    struct { float r, g, b; };
    float arr[3];
};

私はそれをお勧めしません - それは混乱につながります.


追加

エイドリアンが回答で指摘したように、匿名の構造体メンバーとのこの結合は、ISO C++ ではサポートされていません。これは GNU G++ で動作します (「 」をオンにするとサポートされないという不満があります-Wall -ansi -pedantic)。これは、構造体の要素名がすべての構造体で一意である必要があり、構造内のオフセットを取得するために短縮表記法を使用できた、標準化以前の C 時代 (K&R 1st Edn 以前) を思い起こさせます。他の構造タイプのメンバー名を使用する - 無秩序の形。私が C を使い始めた頃には (かなり前ですが、K&R1 以降)、それはすでに歴史的な使用法でした。

(2 つの構造体の) 匿名共用体メンバーで示された表記法は、C11 (ISO/IEC 9899:2011) でサポートされていますが、C 標準の以前のバージョンではサポートされていません。ISO/IEC 14882:2011 (C++11) のセクション 9.5 は無名共用体を規定していますが、GNU (4.9.1) は" " を識別するg++で示されるコードを受け入れません。-pedanticwarning: ISO C++ prohibits anonymous structs [-Wpedantic]

この考え方は混乱を招くので、それが標準的でないことは特に心配していません。私はこのタスクにこのメカニズムを使用しません (また、匿名の構造体を共用体で使用することには、たとえそれが有益であったとしても) 慎重です)。


懸念が提起されました:

3 つ (xyz、rgb、および配列) は、必ずしも整列しているわけではありません。

それは 3 つの要素の結合です。3 つの要素は同じアドレスから始まります。最初の 2 つは、3 つの float 値を含む構造体です。継承はなく、さまざまなレイアウトなどを提供する仮想関数もありません。構造は、3 つの要素が連続して配置されます (実際には、標準でパディングが許可されていても)。配列も同じアドレスから開始し、構造体で「パディングなし」を条件として、要素は 2 つの構造体をオーバーラップします。問題があるとは本当に思いません。

于 2009-01-30T05:59:23.930 に答える
4

参照?

template<typename T>
struct vertex {
    vertex() :
        r(data[0]), g(data[1]), b(data[2]),
        x(data[0]), y(data[1]), z(data[2])
    {
    }

    T *operator *() {
        return data;
    }

    const T *operator *() const {
        return data;
    }

    T data[3];
    T &r, &g, &b;
    T &x, &y, &z;
};
于 2009-01-30T13:05:23.710 に答える
3

他の人が述べたように、ユニオンでこれを取得できます。このように同じ構造体に色と位置をオーバーロードするのは良い考えではないかもしれません (たとえば、2 つの色を追加すると通常 1.0 に飽和することを意味しますが、ベクトルの追加は直線的に行われます)。これはまったく問題なく、GL/DirectX などとデータを交換する手段として広く受け入れられています。

ただし、同じ関数スコープ内の異なるエイリアスで同じメンバーを参照することは避けることをお勧めします。これは、load-hit-store と呼ばれる厄介なハードウェア ストールに陥るからです。特に、次のことができる場合はこれを避けてください。

vector foo; 
foo.x = 1.0f;
return foo[0] + foo[1];
于 2009-01-30T06:05:20.733 に答える
3

次の構造には、要求された動作があります。

struct vertex
{
private:
    float data[3];
public:
    float &x, &y, &z;
    float &r, &g, &b;

    vertex() : x(data[0]), y(data[1]), z(data[2]), r(data[0]), g(data[1]), b(data[2]) {
    }

    float& operator [](int i) { 
        return data[i];
    }
};
于 2015-03-24T16:38:04.647 に答える
2

必要なものを得るためにマクロマジックを行うことができると思います。しかし、それは醜く見えます。3 つの異なるタイプに同じ構造体、頂点を使用するのはなぜですか? 色のクラスを定義できないのはなぜですか? また、頂点と色は同じではないことに注意してください。頂点に何かを変更すると、両方に同じクラスがある場合、色にも影響します。

于 2009-01-30T05:59:39.077 に答える
2

質問を正しく理解したかどうかわかりません。しかし、構造体/クラスへのアクセスのような配列を提供するには、operator[] をオーバーロードする必要があるようです。ここに記載されている例を参照してください:演算子のオーバーロード

于 2009-01-30T06:11:22.127 に答える
1

私の意見では、少なくとも与えられた例については悪い考えです。欠点は、これに対するほぼすべての解決策で、おそらく「rgb」インスタンスを「xyz」インスタンスに/から自由に割り当てることができることです。おそらく賢明で正しいことはめったにありません。つまり、便利な型の安全性を放棄するリスクがあります。

個人的には、あなたが与える例では、ベースboost::array<float,3>または類似のものから rgb および xyz タイプをサブクラス化します。したがって、どちらも operator[] を継承し、配列を期待する関数に渡すことができ、色/座標を期待するものにはより型安全に渡すことができます。xyz または rgb を配列として扱いたいと思うことはよくありますが、xyz を rgb として、またはその逆として扱いたいと思うことはめったにありません。(rgb IS-A 配列: OK. xyz IS-A 配列: OK. rgb IS-A xyz ???? そうは思いません!)

もちろん、これは x,y,z & r,g,b へのアクセスはoperator[](...)、メンバーに直接ではなく、アクセサー (適切な に転送) によって行う必要があることを意味します。(そのためには C# のプロパティが必要です)。

于 2009-01-30T13:49:50.250 に答える
0

次のように、変数への参照を追加してみてください。

struct test {
        float x, y, z;
        float &r, &g, &b;

        test() : r(x), g(y), b(z) {}
    };

ただし、構造は大きくなります (12 バイトから 40 バイト)。

[] を使用するには、前述のように operator[] のオーバーロードを使用します。

于 2009-01-30T13:07:19.103 に答える
0

値メンバーを指す参照メンバーの使用に関する警告です。そのようなオブジェクトをコピーする場合 (値による転送など) は、コピー コンストラクター (およびおそらく代入演算子) を定義する必要があります。デフォルトのコピー コンストラクターは、参照メンバーが新しいオブジェクトの値メンバーではなく、元のオブジェクトの値メンバーを指すコピーを残します。これは確かにあなたが望むものではありません。

既に指摘したように、最終的にはより大きなオブジェクトになることを考えると、参照メンバーよりもアクセサー メソッドを使用することをお勧めします。

于 2009-03-08T16:54:38.270 に答える