2

C ++での前回のプロジェクトから何年も経ちましたが、これを行う方法を思い出せません。

サンプル(擬似コード):

    MyClass
    {
    public :
        float x;
        float y;
        float z;
    }

    main.cpp

    void MyFunction(void)
    {
        MyClass *myclass = new MyClass(); 
        float x = myclass->x;

        //want I want :
        float *xyz = myclass->xyz;
    }

これを行う方法 ?

どうもありがとうございました、そして私の貧弱な英語をお詫びします。

[編集]これは現在の概念にすぎませんが、目標はGLSL(OpenGL Shader for GPU)のvec4クラスの近くにあります。Vec4は、4つの値(x、y、z、w)を持つ数学ベクトルクラスです。このサンプルのように値を取得/割り当てることができます:

vec4 vectorA = vec4(1.0, 1.0, 1.0, 1.0);
vectorA.x = 2.0;
vec2 vectorB = vectorA.xy;
vec3 vectorC = vectorA.xxx;

など(つまり、VectorC.x = 2.0、vectorC.y = 2.0、vectorC.z = 2.0)

4

3 に答える 3

8

名前のない構造を使用する:

union Vector
{
    struct 
    {
        float x;
        float y;
        float z;
    };
    float xyz[3];
};

次に、包含構造を暗黙的に参照せずにコンポーネントにアクセスできます。

int main()
{ 
    Vector* vec = new Vector();
    vec->x = 50;
    vec->y = 30;
    vec->xyz[2] = vec->xyz[0] + vec->xyz[1]; // vec->z == 80
    delete vec;
    return 0;
}

もちろん、このユニオンを別の構造/クラスでラップして、同じ効果を得ることができます。

class MyClass
{
public:
    union
    {
        struct 
        {
            float x;
            float y;
            float z;
        };
        float xyz[3];
    };
};

また、なぜヒープ上に構造を作成するのですか(「新規」を使用)?スタックに割り当てませんか?

編集:ああ、わかりました。まあ、それは間違いなく実行可能ですが、GLSLとの互換性をできるだけ多くしたい場合にのみ価値があります。アイデアは、各コンポーネントのバリエーションの参照を格納する「プロキシ」を作成することです。トレードオフは、8バイトのメモリを使用する代わりにvec2が40バイトを使用することです。それは明らかにvec3とvec4でははるかに悪化します

class vec2
{
    // private proxy, auto-convertible into vec2
    struct proxy2
    {
        // store references, not values!
        proxy2(float &x, float &y) : x(x), y(y) {}
        // implicit conversion to vec2
        operator vec2() { return vec2(x, y); }
        // support assignments from vec2
        proxy2& operator=(const vec2& vec) 
        { 
            x = vec.x; 
            y = vec.y; 
            return *this; 
        }
    private:
        // hide copy and assignment operators
        proxy2(const proxy2&);
        proxy2& operator=(const proxy2&);
        // hide member variables
        float& x;
        float& y;
    };

public:
    vec2(float _x, float _y) 
        : x(_x), y(_y) 
        , xx(x, x), xy(x, y), yx(y, x), yy(y, y)
    {}

    vec2(const vec2& vec)
        : x(vec.x), y(vec.y)
        , xx(x, x), xy(x, y), yx(y, x) , yy(y, y)
    {}

    float x;
    float y;
    proxy2 xx;
    proxy2 xy;
    proxy2 yx;
    proxy2 yy;
};

このクラスを使用すると、GLSLが提供するものにかなり近い構文を取得できます。

vec2 v(1.0f, 2.0f);
vec2 vxx = v.xx; // 1, 1
vec2 vyx = v.yx; // 2, 1
vec2 vxy = v.xy; // 1, 2
vec2 vyy = v.yy; // 2, 2

v.yx = vec2(3, 4); // 4, 3
v.y = 5;           // 4, 5

vec2::proxy2 proxy = v.xx;     // compile error
v.xx = vec2::proxy2(v.x, v.y); // compile error

これを拡張して、およびをそれぞれサポートvec3し、vec4単純に派生させるには、各コンポーネントバリエーションのメンバーを作成および構造化して宣言します(27は27、は64のみ)。vec2vec3proxy3proxy4vec3vec4

EDIT2:新しいバージョン。余分なスペースをまったく必要としません。繰り返しますが、組合が救助に!テンプレートに変換proxy2し、コンポーネントに一致するデータメンバーを追加すると、vec2安全にユニオンに入れることができます。

class vec2
{
    // private proxy, auto-convertible into vec2
    template <int x, int y>
    struct proxy2
    {
        // implicit conversion to vec2
        operator vec2()
        { 
            return vec2(arr[x], arr[y]); 
        }
        // support assignments from vec2
        proxy2& operator=(const vec2& vec) 
        { 
            arr[x] = vec.x; 
            arr[y] = vec.y; 
            return *this; 
        }
    private:
        float arr[2];
    };

public:
    vec2(float _x, float _y) 
        : x(_x), y(_y) 
    {}

    vec2(const vec2& vec)
        : x(vec.x), y(vec.y)
    {}

    union
    {
        struct 
        {
            float x;
            float y;
        };
        proxy2<0, 0> xx;
        proxy2<0, 1> xy;
        proxy2<1, 0> yx;
        proxy2<1, 1> yy;
    };
};

これがあなたが求めているものであることを願っています。

EDIT3:しばらく時間がかかりましたが、変更なしでフラグメントシェーダーを実行できる、動作するGLSLエミュレーションライブラリ(スウィズリングを含む)を思いつきました。それでも興味がある場合は、ご覧ください。

于 2012-10-23T08:24:09.183 に答える
3

C ++はのような構文に対応できますがvec.xyx、書くのは簡単ではありません。そして、機能を1つずつ追加してもそこに到達することはできません。要件をリストし、ツールを選択して、ストレートショットを作成することをお勧めします。

何が必要:

  1. 次のようなストレージクラスstd::array
  2. x、、yxy、、、xzxyz、、、xzx…</li> という名前のメンバー
  3. それらのメンバーを目的の出力に変換するもの
  4. 出力に目的のセマンティクスを与えるためのタイプ

最初の要件は単純です:を使用しますstd::array

次に、3 + 3 ^ 2 + 3 ^ 3=39のメンバーを定義する必要があります。これはコピーアンドペーストで実行できますが、テンプレートメタプログラミングを使用したほうがよいでしょう。zメンバーと一緒にそれは必須です。

メンバーのタイプは無意味ですが、配列から名前付き要素を選択する方法をコンパイラーに指示する必要があります。

例:

selection_vector< 0, 1, 0 > xyx;
selection_vector< 0, 1, 1 > xyy; // ad nauseam

理想的には、これらのメンバーは状態のない要素を選択する方法を知っていますが、それらはで初期化されthis、それぞれ1つのポインターを使用する必要があります。したがって、各3ベクトルオブジェクトは312バイトを浪費することに注意してください。

メンバーに何かをさせるには、変換関数を定義する必要があります。だからあなたは次のようなものを持っています

selection_vector::operator array3_type() { return { ptr[0], ptr[1], ptr[2] }; }

暗黙の変換関数は、のほかに関数の引数として割り当てと受け渡しを実行するときに適用されますthisが、他の多くの状況では適用されません。したがって、取得するvec.xyx.xvec.xyx[ 1 ]selection_vectorタイプを取得するには、追加のメンバーを定義する必要があります。

クレイジーな型と演算子のオーバーロードのウェブを定義すると、いくつかのキーストロークを節約できるようになります…</ p>

マイナーな妥協

本当に妥協したくないようですが、->*オペレーターは言及する価値があります。これは、添え字を実装するための最良の非メンバー演算子のオーバーロードです。

これにより、次のようなパターンが可能になります

xyx_type xyx;

template< typename vec >
my_3vector< vec > operator->* ( vec &&v, xyx_type )
    { return { v[0], v[1], v[2] }; }

std::array< float, 3 > a { 0.5, 1.5, 9 };

my_3vector< … > b = a->*xyx;

my_3vector簡単に作成std::arrayして、テンプレートメタプログラミングを回避することもできます。プリプロセッサxyx_typeのメタプログラミングも回避するために列挙を作成します。

->*演算子はの代わりになり.ます。->*これにより、作業が非常に簡単になりますが、優先順位がおかしいことに注意してください。それはより低く、あなたはそれがピアである.->期待するでしょう。

于 2012-10-23T08:38:19.453 に答える
2

これが可能な別の解決策です。@gwiazdorrrによって投稿されたユニオンベースの例のわずかなバリエーションです。それは仮定します

#include <cassert>
#include <algorithm>
#include <stdexcept>

struct MyClass
{
    enum { size = 3 };

    typedef float& reference;
    reference x;
    reference y;
    reference z;

    MyClass() 
        : x(xyz[0] = 0), y(xyz[1] = 0), z(xyz[2] = 0)
    {}
    MyClass(float x, float y, float z)
        : x(xyz[0] = x), y(xyz[1] = y), z(xyz[2] = z)
    {}
    MyClass& operator=(MyClass const& other)
    {
        std::copy(other.xyz, other.xyz + size, xyz);
        return *this;
    }

    // convenient indexed access
    reference operator[](std::size_t index)
    {
        if (index < size)
            return xyz[index];
        else
            throw std::out_of_range("index not less than size");
    }

    // raw data access
    float* data() { return xyz; }

private:
    float xyz[size];
};

int main()
{
    MyClass c1;
    MyClass c2(1, 2, 3);
    c1 = c2;
    assert(c1.data()[0] == c2[0]);
    assert(c1.data()[1] == c2[1]);
    assert(c1.data()[2] == c2[2]);

    MyClass c3(c2);
    assert(c2[0] == c3.x);
    assert(c2[1] == c3.y);
    assert(c2[2] == c3.z);
}

私はC++11にアクセスできないと想定したため、コンストラクターでの初期化体操を行いました。

于 2012-12-12T17:12:24.923 に答える