Указатель участника вложенных данных - невозможно?

StackOverflow https://stackoverflow.com/questions/3439074

  •  27-09-2019
  •  | 
  •  

Вопрос

Образующийся образец пониженного кода не делает ничего полезного, но два последующих задания для указателя элемента данных. Первые присвоенные работы, второй дает ошибку компилятора. Предположительно, потому что его до вложенный член.

Вопрос будет: действительно ли просто невозможно позволить указатель участника указывать на вложенный элемент или мне там не пропускаю какой-либо модный синтаксис?

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

ATM Я работаю, используя байтовые смещения и много литейных. Но это уродливо, я бы лучше хотел использовать эти указатели члена.

Да, я знаю, что вопрос, безусловно, вырезал раньше (например, почти любой вопрос). Да, я искал заранее, но не нашел удовлетворительного ответа.

Спасибо за ваше время.

Это было полезно?

Решение

Афайк, это невозможно. Указатель-член может быть сформирован только путем выражения типа &qualified_id, что не ваше дело.

Решение Фа Сокола, вероятно, является наиболее подходящим.

Другие советы

Я предполагаю, что вы пытаетесь получить указатель на 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;
}

Вместо указателя участника вы можете использовать функтор, который возвращает float* когда дано экземпляр Material; изменить тип ParamToAnimate к чему-то вроде:

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

На стороне плюса это портативное - но на нижнем идетном, он требует значительного количества кода котеля и имеет значительное количество времени выполнения.

Если это критично, я бы испытывал соблазн придерживаться метода смещения.

По сути, вы пытаетесь получить указатель на плавающую переменную, которую вы можете оживить. Почему бы не использовать 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. Макету-совместимые POD-структуры и POD-профсоюзы описаны в 9.2. Несомненно

§9.2

16

Если POD-Union содержит два или более структурных структуров, которые разделяют общую начальную последовательность, и если объект POD-Union в настоящее время содержит один из этих структур POD, разрешено проверять общую исходную часть любого из них. Два 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

Два типа Pod-struck (пункт 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