11

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

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

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

是的,我知道这个问题之前肯定出现过(就像几乎所有问题一样)。是的,我事先搜索过,但没有找到满意的答案。

谢谢你的时间。

4

8 回答 8

5

我假设您正在尝试获取指向 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;
}
于 2010-08-09T10:31:49.387 回答
4

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

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

于 2010-08-09T10:36:15.330 回答
3

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

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

从好的方面来说,它是可移植的——但在不利的方面,它需要大量的样板代码并且运行时开销很大。

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

于 2010-08-09T11:26:32.407 回答
2

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

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-structs,它们共享一个共同的初始序列,并且如果 POD-union 对象当前包含这些 POD-structs 之一,则允许检查其中任何一个的共同初始部分。如果对应的成员具有一个或多个初始成员序列的布局兼容类型(并且对于位域,具有相同的宽度),则两个 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-struct(第 9 条)类型具有相同数量的非静态数据成员,并且相应的非静态数据成员(按顺序)具有布局兼容类型(3.9),则它们是布局兼容的。

于 2019-05-12T17:45:44.770 回答
1

基本上,您正在尝试获取指向可以设置动画的浮点变量的指针。为什么不使用float*. 您遇到的问题是BrightnessMaterial 的成员,但是对于编译器来说,它是而不是Red的成员。使用应该可以解决您的问题。ColorMaterialfloat*

于 2010-08-09T10:32:31.613 回答
0

您可以简单地重构,使您根本没有嵌套结构。添加一个设置器,然后将颜色解压缩到其组件中,这样现有代码就不需要太多更改,然后从那里开始。

您还可以采用一个可选的第二个指针来挖掘嵌套类型。与您当前的方法相比,查看您是否需要第二个参数的单个测试可能证明足够好,并且如果稍后出现其他字段,则更容易扩展。

更进一步,您将拥有一个MaterialPointer带有虚拟Dereference方法的基类。案例类可以处理简单的成员,派生类处理嵌套成员以及查找它们所需的任何附加信息。然后工厂可以生产MaterialMember*适当类型的对象。当然,现在你被堆分配困住了,所以这可能有点太远了,不实用。

于 2010-08-09T13:09:02.210 回答
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;
于 2010-08-09T15:39:57.660 回答
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; }
于 2011-05-01T00:36:27.333 回答