愚蠢的简化代码示例没有做任何有用的事情,而是对数据成员指针进行两次后续分配。第一个分配工作,第二个分配给出编译器错误。大概是因为它是一个嵌套的成员。
问题是:是否真的不可能让成员指针指向嵌套成员,或者我错过了任何花哨的语法?
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我正在使用字节偏移和大量的强制转换。但这很难看,我最好使用那些成员指针。
是的,我知道之前肯定会出现这个问题(几乎与任何问题一样)。是的,我事先搜查过,但没有找到令人满意的答案。
感谢您的时间。
答案 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的成员,但Red
是Color
的成员,而不是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; }