Pergunta

A amostra de código reduzida em apagamento não faz nada útil, mas duas atribuições subsequentes a um ponteiro de membro de dados. A primeira atribuição funciona, o segundo fornece um erro do compilador. Presumivelmente porque é para um membro aninhado.

Pergunta seria: realmente não é possível deixar um ponteiro de membro apontar para um membro aninhado ou estou perdendo alguma sintaxe sofisticada lá?

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, estou trabalhando usando compensações de bytes e muitos elencos. Mas isso é feio, é melhor eu gostar de usar esses indicadores de membros.

Sim, eu sei que essa pergunta certamente surgiu antes (como quase qualquer pergunta). Sim, procurei de antemão, mas não encontrei resposta satisfatória.

Obrigado pelo seu tempo.

Foi útil?

Solução

Afaik, isso não é possível. Um ponteiro para membro só pode ser formado por uma expressão do tipo &qualified_id, que não é o seu caso.

A solução do Vite Falcon é provavelmente a mais apropriada.

Outras dicas

Suponho que você esteja tentando pegar o ponte Red. Já que isso é definido na estrutura Color O tipo de ponteiro é Color::*. Portanto, seu código deve ser:

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

Para usá -lo, você precisa vinculá -lo a uma instância de Color por exemplo:

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

EDITAR: Não é possível tornar a função de animação um modelo? Por exemplo:

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

Em vez de um ponteiro de membro, você pode usar um functor que retorna um float* Quando recebeu uma instância de Material; Alterar o tipo de ParamToAnimate Para algo como:

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

No lado positivo, é portátil - mas, no lado negativo, requer uma quantidade significativa de código de caldeira e tem uma sobrecarga significativa de tempo de execução.

Se isso for crítico, eu ficaria tentado a seguir o método de deslocamento.

Basicamente, você está tentando obter um ponteiro para uma variável de flutuação que você pode animar. Por que não usar float*. O problema que você está tendo lá é que Brightness é um membro do material, no entanto, Red é um membro de Color e não Material, para o compilador. Usando float* deve resolver seu problema.

Não é possível. Mas há uma solução alternativa muito próxima do que você deseja alcançar. Envolve colocar o membro aninhado em uma união junto com uma estrutura anônima "compatível com layout". A desvantagem é uma interface um pouco inchada e a necessidade de manter as definições de estruturas de irmãos em sincronia.

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

Se dois tipos T1 e T2 são o mesmo tipo, T1 e T2 são tipos compatíveis com layout. [Nota: as enumerações compatíveis com o layout são descritas em 7.2. As estruturas de pod e pod-unions compatíveis com layout são descritas em 9.2.

§9.2

16

Se uma união de pod contiver duas ou mais estruturas de pod que compartilham uma sequência inicial comum, e se o objeto POD-Union atualmente contiver uma dessas estruturas de pod, é permitido inspecionar a parte inicial comum de qualquer uma delas. Duas estruturas de pods compartilham uma sequência inicial comum se os membros correspondentes tiverem tipos compatíveis com layout (e, para campos de bits, as mesmas larguras) para uma sequência de um ou mais membros iniciais.

Ninho múltiplo também é possível:

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

Dois tipos de estrutura de pod (cláusula 9) são compatíveis com o layout se tiverem o mesmo número de membros de dados não estáticos, e os membros correspondentes de dados não estatísticos (em ordem) têm tipos compatíveis com layout (3.9).

Você pode simplesmente refatorar para que não tenha a estrutura aninhada. Adicione um setter do que descompactar a cor em suas peças componentes para que o código existente não precise mudar muito e vá a partir daí.

Você também pode pegar um segundo ponteiro opcional que se aproxima do tipo aninhado. Um único teste para ver se você precisa do segundo parâmetro pode ser bom o suficiente em comparação com o seu método atual e seria mais facilmente estendido caso os campos adicionais aparecessem posteriormente.

Dê um passo adiante e você terá uma base MaterialPointer classe com um virtual Dereference método. A classe do caso pode lidar com membros simples, com classes derivadas lidando com membros aninhados com as informações adicionais necessárias para encontrá -los. Uma fábrica pode então produzir MaterialMember* objetos do tipo apropriado. Claro, agora você está preso a alocações de heap, então isso provavelmente é um pouco longe demais para ser prático.

Como em algum momento você precisa de um ponteiro para os dados reais, isso pode ou não funcionar para você:

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;

Que tal herança em vez de composição?

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; }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top