嵌套数据成员指针 - 不可能?

时间:2010-08-09 10:22:20

标签: c++ member-pointers

愚蠢的简化代码示例没有做任何有用的事情,而是对数据成员指针进行两次后续分配。第一个分配工作,第二个分配给出编译器错误。大概是因为它是一个嵌套的成员。

问题是:是否真的不可能让成员指针指向嵌套成员,或者我错过了任何花哨的语法?

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我正在使用字节偏移和大量的强制转换。但这很难看,我最好使用那些成员指针。

是的,我知道之前肯定会出现这个问题(几乎与任何问题一样)。是的,我事先搜查过,但没有找到令人满意的答案。

感谢您的时间。

8 个答案:

答案 0 :(得分:5)

我假设您正在尝试获取指向数据库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;
}

答案 1 :(得分:4)

AFAIK,这是不可能的。指向成员的指针只能由&qualified_id类型的表达式构成,而不是你的情况。

Vite Falcon的解决方案可能是最合适的。

答案 2 :(得分:3)

当给定float*的实例时,您可以使用返回Material的仿函数代替成员指针;将ParamToAnimate的类型更改为:

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

从好的方面来说,它是可移植的 - 但是在缺点方面,它需要大量的样板代码并且具有显着的运行时开销。

如果这对性能至关重要,我很想坚持使用偏移方法。

答案 3 :(得分:2)

基本上你正在尝试获取一个可以设置动画的浮点变量的指针。为什么不使用float*。您遇到的问题是Brightness是Material的成员,但RedColor的成员,而不是Material的成员。使用float*可以解决您的问题。

答案 4 :(得分:1)

不可能。但是有一种解决方法非常接近您想要实现的目标。它涉及将嵌套成员与“布局兼容”匿名结构一起放入联合。缺点是接口有点膨胀,并且需要保持同级结构的定义同步。

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联合包含两个或多个共享共同点的POD结构   初始序列,如果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结构(第9节)类型具有   相同数量的非静态数据成员,以及相应的非静态   数据成员(按顺序)具有与布局兼容的类型(3.9)。

答案 5 :(得分:0)

您可以简单地重构,使您根本没有嵌套结构。添加一个setter,而不是将颜色解压缩到它的组件部分,这样现有的代码就不需要做太多改变了,从那里开始。

您还可以使用可选的第二个指针来挖掘嵌套类型。与您当前的方法相比,单个测试可以证明您是否需要第二个参数,并且如果以后出现其他字段,则可以更轻松地进行扩展。

更进一步,您有一个基础MaterialPointer类,其中包含虚拟Dereference方法。 case类可以处理简单成员,派生类处理嵌套成员以及查找它们所需的任何其他信息。然后工厂可以生成相应类型的MaterialMember*个对象。当然,现在你已经陷入了堆分配,所以这可能有点太落实了。

答案 6 :(得分:0)

由于在某些时候您需要指向实际数据的指针,这可能适用于您,也可能不适合您:

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;

答案 7 :(得分:0)

继承而不是组合怎么样?

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