2010-08-09 11 views
9

La muestra de código reducido engañoso no hace nada útil sino dos asignaciones posteriores a un puntero de miembro de datos. La primera asignación funciona, la segunda da un error de compilación. Presumiblemente porque es un miembro anidado.Puntero de miembro de datos anidados: ¿no es posible?

La pregunta sería: ¿Realmente no es posible dejar que un apuntador miembro apunte a un miembro anidado o me falta alguna sintaxis de fantasía allí?

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 Estoy trabajando con el uso de compensaciones de bytes y una gran cantidad de moldes. Pero eso es feo, me gustaría usar esos indicadores de miembros.

Sí, sé que la pregunta seguramente surgió antes (como casi cualquier pregunta). Sí, busqué de antemano pero no encontré una respuesta satisfactoria.

Gracias por su tiempo.

+0

jpalecek es correcto; La respuesta a tu pregunta es no. Pero lo que realmente estás buscando es una solución a un problema. Con una reestructuración menor de sus datos, puede encontrar un tipo que apunte a los cuatro flotadores. (Consulte a continuación.) –

Respuesta

4

AFAIK, esto no es posible. Un puntero a miembro solo puede estar formado por una expresión de tipo &qualified_id, que no es su caso.

La solución de Vite Falcon es probablemente la más adecuada.

+0

También me temo que simplemente no es posible. Tal vez tenga que seguir con mi solución de compensación de bytes. Usar punteros de flotación absolutos no sería lo mismo. –

+0

Aunque no me gusta la referencia a Falcon, su respuesta es probablemente la correcta. No es posible, por desgracia. –

5

Supongo que está tratando de obtener el puntero al miembro de datos Red. Como esto se define en la estructura Color, el tipo del puntero es Color::*. Por lo tanto, el código debe ser:

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

Para utilizarlo, es necesario para obligar a éste a una instancia de Color por ejemplo:

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: ¿No es posible hacer la función de animación ¿una plantilla? Por ejemplo:

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

Esto tiene un gran problema, que no puede animar el brillo con esta arquitectura. – jpalecek

+0

@jpalecek: Sí, tienes razón. Me estaba concentrando más en la sintaxis. – Naveen

+0

Uhm, sí, pero usar punteros diferentes haría que todo no tenga sentido. Quiero un único puntero que almacene qué flotante en el material (o sus miembros anidados) tiene que ser animado. Y en realidad, por supuesto, tengo aún más miembros anidados en el material. Teóricamente debería ser posible. Mi solución con los desplazamientos de bytes y muchos moldes funciona. Es solo una cosa de sintaxis. –

2

Básicamente está tratando de obtener un puntero a una variable flotante que puede animar. Por qué no usar float*. El problema que tiene es que Brightness es miembro de Material, sin embargo, Red es miembro de Color y no Material, al compilador. El uso de float* debería resolver su problema.

+0

Un puntero flotante simple sería un puntero absoluto a una única ubicación de memoria. No se podría usar en varios objetos materiales y se volvería inválido si el material cambia su ubicación de memoria. –

+1

Por lo que yo entiendo, un puntero siempre será inválido si el material cambia su ubicación en la memoria. Ningún puntero sigue el cambio en la ubicación de la memoria. –

+2

¡Los punteros de los miembros siguen las ubicaciones de la memoria! Solo son desplazamientos relativos en un objeto. Debe especificar una instancia adicional para acceder a ellos. –

2

En lugar de un puntero de miembro, puede usar un funtor que devuelve float* cuando se le da una instancia de Material; cambiar el tipo de ParamToAnimate a algo como:

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

En el lado positivo, es portátil - pero a la baja, se requiere una cantidad significativa de código repetitivo y tiene significativa sobrecarga de tiempo de ejecución.

Si esto es crítico para el rendimiento, me sentiría tentado a seguir con el método de compensación.

+0

Entendemos su idea, pero sí, es fundamental para el rendimiento. Estoy trabajando en un motor 3D en tiempo real. –

+1

Entonces el hack/método de compensación es probablemente mejor. –

0

Puede simplemente refactorizar de forma tal que no tenga la estructura anidada. Agregue un colocador que desempaquete el color en sus partes componentes para que el código existente no tenga que cambiar mucho y vaya desde allí.

También podría tomar un segundo puntero opcional que cava en el tipo anidado.Una sola prueba para ver si necesita el segundo parámetro puede ser lo suficientemente buena en comparación con su método actual, y se extendería más fácilmente si aparecen campos adicionales más adelante.

Da un paso más y tienes una clase base MaterialPointer con un método virtual Dereference. La clase de caso puede manejar miembros simples, con clases derivadas que manejan miembros anidados con la información adicional que necesitan para encontrarlos. Una fábrica puede producir MaterialMember* objetos del tipo apropiado. Por supuesto, ahora estás atascado con las asignaciones de montón, por lo que es probable que sea un poco demasiado lejos para ser práctico.

+0

Todas esas son posibles alternativas. Pero también son más complicados y/o menos efectivos que mi solución existente con compensaciones de bytes y moldes. –

0

Dado que en algún momento se necesita un puntero a los datos reales, esto puede o puede no funcionar para usted:

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

Sí, ese es otro puntero con un tipo diferente. No ayudaría a que todo sea más fácil y elegante. –

0

¿Qué hay de la herencia en lugar de composición?

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