سؤال

وأنا متأكد من هذا الأمر ممكن، لأنني متأكد من أنني قد رأيت عليها القيام به. أعتقد أنه رائع، ولكنني لن نقبل إجابات على غرار "هذه فكرة رهيبة ل____".

ويقول لدينا البنية الأساسية.

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;

ومن الناحية المثالية أن بناء الجملة الثالث لا يمكن تمييزها من صفيف. وهذا هو، إذا وجهت arr كمعلمة إشارة إلى وظيفة تتوقع مجموعة من العوامات في الذي سيتم تخزين البيانات (على سبيل المثال العديد من وظائف برنامج OpenGL glGet)، انها ستعمل على ما يرام.

ما رأيك؟ ممكن؟ ممكن ولكن الغباء؟

هل كانت مفيدة؟

المحلول

ما أود القيام به هو جعل من يمكنهم الدخول:

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_;
}

نصائح أخرى

والبنيات المتداخلة بلا أسماء في اتحاد ليست معيار 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 وتطفو فيرتكس :: * CONST فير" يعني أن فير هو مؤشر إلى عضو تعويم البنية فيرتكس. و[3] يعني أنه مجموعة من 3 من هذه. في المشغل زائد []، فهرسة هذه المجموعة وألغى الإشارة القيمة وعضوا بيانات مؤشر إلى وإرجاع قيمة.

وبالإضافة إلى ذلك، يجب أن تعمل هذه الطريقة بغض النظر عن القضايا التعبئة - مترجم حر في لوحة الهيكل فيرتكس إلا أنه يحب وانها سوف لا تزال تعمل على ما يرام. سيتم تشغيل اتحادا مجهول في مشاكل إذا كانت معبأة في يطفو بشكل مختلف.

استخدم اتحاد؟

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 1 EDN)، عندما كانت أسماء عناصر الهيكل لتكون فريدة من نوعها في جميع الهياكل، وكنت قد تستخدم الرموز التعاقد للوصول إلى إزاحة داخل الهيكل، وكنت قد استخدام أسماء الأعضاء من أنواع هيكل أخرى - شكل من أشكال الفوضى. بحلول الوقت الذي بدأت باستخدام C (منذ وقت طويل، ولكن بعد K & R1)، وكان ذلك الاستعمال التاريخي بالفعل.

والتدوين تظهر مع أعضاء النقابة مجهول (لالهيكلين) معتمد من قبل C11 (ISO / IEC 9899: 2011)، ولكن ليس عن طريق الإصدارات السابقة من مستوى C. القسم 9.5 من ISO / IEC 14882: 2011 (C ++ 11) تنص على النقابات غير معروفة ولكن GNU g++ (4.9.1) لا تقبل الكود الظاهر مع -pedantic، وتحديد "warning: ISO C++ prohibits anonymous structs [-Wpedantic]"

.

ومنذ هذه الفكرة سوف يؤدي إلى الارتباك، وأنا لست بقلق خاص أنه ليس المعيار، أنا لن تستخدم آلية لهذه المهمة (وسأكون خشية من استخدام هياكل مجهولة في اتحاد حتى لو كان مفيدا).


ووأثير قلق:

<اقتباس فقرة>   

والثلاثة (س-ص ض، ص، ز-B ومجموعة) لا تتلاءم بالضرورة.

وبل هو الاتحاد مع ثلاثة عناصر. تبدأ العناصر الثلاثة في نفس العنوان. الأولين هي الهياكل التي تحتوي على 3 قيم التعويم. ليس هناك الميراث وعدم وجود وظائف افتراضية لتقديم تصاميم مختلفة، وما إلى ذلك سيتم وضع الهياكل بها مع العناصر الثلاثة متجاورة (في الواقع، حتى لو كان يسمح المعيار الحشو). يبدأ مجموعة أيضا في نفس العنوان، وتخضع ل"لا الحشو" في الهياكل والعناصر تتداخل الهيكلين. أنا في الحقيقة لا أرى أنه لن يكون هناك مشكلة.

ويمكنك الحصول على هذه مع الاتحاد كما ذكر آخرون. الحمولة الزائدة اللون ووضع على نفس هيكل مثل هذا قد لا يكون فكرة جيدة (على سبيل المثال، إضافة لونين يعني عادة تريد أن تشبع إلى 1.0، في حين يحدث مضيفا ناقلات خطيا)، ولكن تتراكب تعويم [] على رأسهم مثل هذا على ما يرام تماما وسيلة مقبولة تماما من تتبادل البيانات مع GL / دايركت / الخ.

وأنصحك تجنب اشارة الى العضو نفسه من الأسماء المستعارة المختلفة في نطاق وظيفة نفسه، وذلك لأن هذا سوف تدفع لك في كشك الأجهزة سيئة يسمى التى ضربها تحميل في متجر. على وجه الخصوص، وتجنب هذا إذا استطعت:

vector foo; 
foo.x = 1.0f;
return foo[0] + foo[1];

والمراجع؟

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;
};

وأعتقد أنك يمكن أن تفعل بعض السحر الكلي للحصول على ما تريد. ولكن من شأنها أن تبدو قبيحة. لماذا كنت تريد استخدام نفس البنية، قمة الرأس لمدة 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];
    }
};

وفكرة سيئة في رأيي، على الأقل في المثال المذكور: الجانب السلبي هو أن للتو عن أي حل لهذا، وربما كنت سوف تكون قادرة على تعيين بحرية حالات "RGB" إلى / من "س ع ص" الحالات، والتي ربما نادرا ما معقول أو صحيحة. أي هل خطر التخلي عن بعض من المفيد سلامة النوع.

وشخصيا، لسبيل المثال تعطي، فما استقاموا لكم فاستقيموا فرعية RGB و XYZ أنواع من boost::array<float,3> قاعدة أو ما شابه ذلك. لذلك كل منهم يرث التشغيل []، يمكن أن تنتقل إلى وظائف توقع المصفوفات، ومرت مع أكثر سلامة نوع من الأشياء تتوقع الألوان / الإحداثيات. انها في كثير من الأحيان تريد لعلاج XYZ أو RGB كما صفيف، ولكنها نادرة تريد لعلاج س ع ص ك RGB أو العكس بالعكس. (RGB هو-A مجموعة: OK س ع ص IS-A مجموعة:.! OK RGB هو-A س ع ص ؟؟؟؟ أنا لا أعتقد ذلك)

وبالطبع هذا يعني الوصول إلى س، ص، ض و ص، ز، ب تحتاج ليكون الى جانب استرجاع (إعادة توجيه إلى operator[](...) مناسبا) بدلا من مباشرة إلى العضو. (كنت بحاجة خصائص C # الصورة لذلك).

ولدي قالب وفئتين ناقل أدناه، واحد مجنون، واحد عاقل. القالب تنفذ بسيطة ثابتة في مجموعة وقت الترجمة من القيم. وهو مصمم لإن شاء subclasses ترث ويستخدم متغير مجموعة المحمية لتجنب الحاجة إلى القفز من خلال الأطواق للوصول إلى مجموعة. (بعض الناس قد لا يحبون مثل هذا التصميم، وأقول، إذا الفئات الفرعية الخاصة بك ويطالب مشغلي الخاص بك فوق طاقتها، واقتران قد يكون فكرة جيدة).

والطبقة مجنون تتيح لك الحصول على المتغيرات عضو يسمى س، ص، ض، وأنه يتصرف مثل مجموعة للمكالمات إلى glGetFloatV. واحد عاقل لديه فقط وظائف استرجاع العاشر ()، ص () ض () ولا يزال يعمل مع glGetFloatV. يمكنك استخدام أي من الدرجة كأساس للكائنات متجهة الأخرى التي قد تمر إلى OpenGL المكتبة. على الرغم من أن الطبقات هي أقل تحديدا إلى نقاط، يمكنك من الواضح أن مجرد القيام بعملية بحث / استبدال لتحويلها إلى فصول RGB اللون.

والطبقة مجنونة مجنونة لأن تكلفة vec.x نحوي السكر بدلا من vec.x () هو 3 متغيرات المرجعية. يمكن أن يستغرق الكثير من المساحة في تطبيق واسع. استخدام الإصدار عاقل بساطة.

template <typename T, int N>
class FixedVector {
protected:
    T arr[N];
public:
    FixedVector();

    FixedVector(const T* a) {
        for (int i = 0; i < N; ++i) {
            arr[i] = a[i];
        }
    }

    FixedVector(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
    }

    FixedVector& operator=(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
        return *this;
    }

    T* operator&() { return arr; }
    const T* operator&() const { return arr; }

    T& operator[](int ofs) { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
    const T& operator[](int ofs) const { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
};

class CrazyPoint :  public FixedVector<float, 3> {
public:
    float &x, &y, &z;

    CrazyPoint()
      : x(arr[0]), y(arr[1]), z(arr[2])
    { arr[0] = arr[1] = arr[2] = 0.0; }

    CrazyPoint(const float* a)
      : x(arr[0]), y(arr[1]), z(arr[2])
    {
        arr[0] = a[0];
        arr[1] = a[1];
        arr[2] = a[2];
    }

    CrazyPoint(float a, float b, float c) 
      : x(a), y(b), z(c)
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

class SanePoint : public FixedVector<float, 3> {
public:
    float& x() { return arr[0]; }
    float& y() { return arr[1]; }
    float& z() { return arr[2]; }

    SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
    SanePoint(float a, float b, float c) 
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);

ويمكنك محاولة إضافة ما يشير إلى المتغيرات، مثل هذا:

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

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

ولكن الهيكل الخاص يحصل على اكبر (من 12 بايت و 40 بايت).

لاستخدام [] على ذلك، استخدام الحمولة الزائدة المشغل []، كما ذكر من قبل.

ومجرد تحذير حول استخدام أعضاء إشارة لافتا إلى أعضاء القيمة. تحتاج إلى تعريف منشئ نسخة (وربما أيضا عامل التعيين)، إذا كنت من أي وقت مضى نسخ مثل كائن (مثل نقله من حيث القيمة). ومنشئ نسخة الافتراضي أترككم مع نسخة التي تشير إلى أعضاء قيمة الكائن الأصلي، وليس تلك الكائن الجديد أعضاء المرجعية. وهذا بالتأكيد ليس ما تريد.

ونظرا كنت أيضا في نهاية المطاف مع الأجسام الكبيرة، كما سبق أن ذكرنا، وأعتقد أن استخدام أساليب استرجاع هو يفضل أن يكون على أفراد المرجعية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top