سؤال

لا تفعل عينة الكود المخفض للحفاظ على أي شيء مفيد ولكن اثنين من المهام اللاحقة لمؤشر عضو البيانات. المهمة الأولى تعمل ، والثاني يعطي خطأ المترجم. يفترض لأنها لعضو متداخل.

سيكون السؤال هو: هل من غير الممكن حقًا السماح لمؤشر العضو يشير إلى عضو متداخل أم أفتقد أي بناء جملة خيالي هناك؟

struct Color {
    float Red;
    float Green;
    float Blue; };


struct Material {
    float Brightness;
    Color DiffuseColor; };


int main() {
    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::Brightness;       // Ok
    ParamToAnimate = &Material::DiffuseColor.Red; // Error! *whimper*
    return 0; }

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

نعم ، أنا أعلم أن هذا السؤال قد نشأ بالتأكيد من قبل (مثل أي سؤال تقريبًا). نعم ، لقد بحثت مسبقًا ولكن لم أجد أي إجابة مرضية.

شكرا على وقتك.

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

المحلول

AFAIK ، هذا غير ممكن. لا يمكن تشكيل مؤشر إلى عضو إلا من خلال تعبير عن النوع &qualified_id, ، وهي ليست حالتك.

من المحتمل أن يكون حل Vite Falcon هو الأنسب.

نصائح أخرى

أفترض أنك تحاول نقل المؤشر إلى Datamember Red. لأن هذا محدد في الهيكل Color نوع المؤشر Color::*. ومن هنا يجب أن يكون الرمز الخاص بك:

int main() {
    float Color::* ParamToAnimate;
    ParamToAnimate = &Color::Red; 
    return 0; }

لاستخدامه ، تحتاج إلى ربطه بمثيل من Color فمثلا:

void f(Color* p, float Color::* pParam)
{
    p->*pParam = 10.0;
}
int main() {
    float Color::* ParamToAnimate;
    ParamToAnimate = &Color::Red; 

    Material m;
    f(&m.DiffuseColor, ParamToAnimate);
    return 0;
}

تعديل: أليس من الممكن جعل وظيفة الرسوم المتحركة قالبًا؟ فمثلا:

template<class T>
void f(T* p, float T::* pParam)
{
    p->*pParam = 10.0;
}
int main() {

    Material m;

    f(&m.DiffuseColor, &Color::Red);
    f(&m, &Material::Brightness);
    return 0;
}

بدلاً من مؤشر العضو ، يمكنك استخدام functor الذي يعيد أ float* عندما تعطى مثيل Material; ؛ تغيير نوع ParamToAnimate إلى شيء مثل:

std::function<float*(Material&)>

على الجانب الإيجابي ، يكون محمولًا - ولكن على الجانب السلبي ، يتطلب كمية كبيرة من رمز Boilerplate ولديه عام تشغيل كبير.

إذا كان هذا أمرًا بالغ الأهمية ، فسوف أميل إلى التمسك بأسلوب الإزاحة.

في الأساس ، تحاول الحصول على مؤشر إلى متغير تعويم يمكنك تحريكه. لماذا لا تستخدم float*. المشكلة التي تواجهها هناك Brightness هو عضو في المواد ، ومع ذلك ، Red هو عضو في Color و لا Material, ، إلى المترجم. استخدام float* يجب حل مشكلتك.

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

struct Color {
    float Red;
    float Green;
    float Blue; };

struct Material {
    float Brightness;
    union {
        struct { // "Layout-compatible" with 'Color' (see citation below)
            float DiffuseColorRed;
            float DiffuseColorGreen;
            float DiffuseColorBlue; };
        Color DiffuseColor; }; };

int main() {
    Material M;

    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::DiffuseColorRed;
    std::cin >> M.*ParamToAnimate;
    std::cout << M.DiffuseColor.Red << std::endl;
    return 0; }

ISO IEC 14882-2003 (C ++ 03):

§3.9

11

إذا كان النوعان T1 و T2 هما نفس النوع ، فإن T1 و T2 هما أنواع متوافقة مع التخطيط. [ملاحظة: يتم وصف التعدادات المتوافقة مع التصميم في 7.2. تم وصف هياكل القرنة المتوافقة مع التصميم ووحدات القرنة في 9.2.

§9.2

16

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

التعشيش المتعدد ممكن أيضًا:

struct Color {
    float Red;
    float Green;
    float Blue; };

struct Material {
    float Brightness;
    Color DiffuseColor; };

struct Wall {
    union {
        struct {
            float SurfaceBrightness;
            struct {
                float SurfaceDiffuseColorRed;
                float SurfaceDiffuseColorGreen;
                float SurfaceDiffuseColorBlue; }; };
        Material Surface; }; };

int main() {
    Wall W;

    float Wall::* ParamToAnimate;
    ParamToAnimate = &Wall::SurfaceDiffuseColorRed;
    std::cin >> W.*ParamToAnimate;
    std::cout << W.Surface.DiffuseColor.Red << std::endl;
    return 0; }

§9.2

14

هناك نوعان من الهيكل (الفقرة 9) متوافقان مع التخطيط إذا كان لديهم نفس عدد أعضاء البيانات غير المستقلين ، ولديهم أعضاء البيانات غير المستقيمين (بالترتيب) لديهم أنواع متوافقة مع التخطيط (3.9).

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

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

خذ هذه الخطوة إلى الأمام ، ولديك قاعدة MaterialPointer الفصل مع افتراضي Dereference طريقة. يمكن لفئة القضية التعامل مع الأعضاء البسيطة ، مع فئات مشتقة من التعامل مع الأعضاء المتداخلين مع أي معلومات إضافية يحتاجون إليها للعثور عليهم. يمكن للمصنع أن ينتج بعد ذلك MaterialMember* كائنات من النوع المناسب. بالطبع ، أنت الآن عالق مع تخصيصات الكومة ، لذلك من المحتمل أن تكون عمليًا جدًا.

نظرًا لأنك في مرحلة ما تحتاج إلى مؤشر للبيانات الفعلية ، فقد ينجح هذا أو لا يعمل من أجلك:

float Material::* ParamToAnimate;
ParamToAnimate = &Material::Brightness;       // Ok
float Color::* Param2;
Param2 = &Color::Red; 

Material mat;
mat.Brightness = 1.23f;
mat.DiffuseColor.Blue = 1.0f;
mat.DiffuseColor.Green = 2.0f;
mat.DiffuseColor.Red = 3.0f;

float f = mat.DiffuseColor.*Param2;

ماذا عن الميراث بدلاً من التكوين؟

struct Color {
    float Red;
    float Green;
    float Blue; };

struct DiffuseColor : public Color {
    };

struct Material : public DiffuseColor {
    float Brightness; };


int main() {
    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::Brightness;       // Ok
    ParamToAnimate = &Material::DiffuseColor::Red; // Ok! *whew*
    return 0; }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top