Указатель на вложенный элемент данных - невозможно?

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

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

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, я работаю, используя смещения байтов и много приведений. Но это ужасно, я бы лучше использовал эти указатели на элементы. 1292 Да, я знаю, что этот вопрос наверняка возникал раньше (как почти любой вопрос). Да, я искал заранее, но не нашел удовлетворительного ответа.

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

10
задан user2672165 23 October 2019 в 15:58
поделиться

6 ответов

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

Решение Vite Falcon, вероятно, наиболее подходящее.

4
ответ дан 3 December 2019 в 22:34
поделиться

В основном вы пытаетесь получить указатель на переменную типа float, которую можно анимировать. Почему бы не использовать float * . Проблема заключается в том, что Яркость является членом Материала, однако Красный является членом Цвет , а не Материал ] в компилятор. Использование float * должно решить вашу проблему.

2
ответ дан 3 December 2019 в 22:34
поделиться

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

std :: function

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

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

3
ответ дан 3 December 2019 в 22:34
поделиться

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

EDIT : нельзя ли сделать функцию анимации шаблон? Например:

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;
}
5
ответ дан 3 December 2019 в 22:34
поделиться

Вы можете просто выполнить рефакторинг, чтобы у вас вообще не было вложенной структуры. Добавьте сеттер, который распаковывает цвет по его составным частям, чтобы существующий код не сильно менялся, и переходите оттуда.

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

Сделайте еще один шаг, и у вас будет базовый класс MaterialPointer с виртуальным методом Dereference . Класс case может обрабатывать простые члены, а производные классы обрабатывают вложенные элементы с любой дополнительной информацией, необходимой им для их поиска. Затем фабрика может производить объекты MaterialMember * соответствующего типа. Конечно, теперь вы застряли с распределением кучи, так что это, вероятно, слишком далеко, чтобы быть практичным.

0
ответ дан 3 December 2019 в 22:34
поделиться

Поскольку в какой-то момент вам понадобится указатель на фактические данные, это может сработать, а может и не сработать:

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;
0
ответ дан 3 December 2019 в 22:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: