我有一个嵌套的结构,我想有一个嵌入成员之一的指向成员的指针:
这合法吗?
struct InnerStruct
{
bool c;
};
struct MyStruct {
bool t;
bool b;
InnerStruct inner;
};
Run Code Online (Sandbox Code Playgroud)
这个:
MyStruct mystruct;
//...
bool MyStruct::* toto = &MyStruct::b;
Run Code Online (Sandbox Code Playgroud)
没问题,但是:
bool MyStruct::* toto = &MyStruct::inner.c;
Run Code Online (Sandbox Code Playgroud)
不是.任何的想法?
谢谢
这里有一些细节是的,它是&MyStruct :: b而不是mystruct :: b; 代码来自自定义RTTI/Property系统.对于每个指定的类,我们保留一个"Property"数组,包括一个Ptr-to-member它的用法如下:
//somewhere else in code...
( myBaseClassWithCustomRTTIPointer)->* toto = true;
Run Code Online (Sandbox Code Playgroud) 几年来我第三次发现自己需要一个不允许提升的项目的侵入性链表(问管理......).
我第三次发现侵入式链表实现我的工作完美,但我真的不喜欢它使用未定义的行为 - 即将指针转换为列表节点到指向包含该列表的对象的指针列表节点.
那可怕的代码目前看起来像这样:
struct IntrusiveListNode {
IntrusiveListNode * next_;
IntrusiveListNode * prev_;
};
template <typename T, IntrusiveListNode T::*member>
class IntrusiveList {
// snip ...
private:
T & nodeToItem_(IntrusiveListNode & node) {
return *(T*)(((char*)&node)-((size_t)&(((T*)nullptr)->*member)));
}
IntrusiveListNode root_;
};
Run Code Online (Sandbox Code Playgroud)
我真的不在乎多么丑陋nodeToItem_,但我想保持公共接口和语法IntrusiveList相同.具体来说,我想指定列表类型的类型IntrusiveList<Test, &Test::node_>而不是IntrusiveList<Test, offsetof(Test, node_)>.
这几乎是2016年 - 有没有办法在不调用未定义的行为的情况下做到这一点?
编辑:评论中有一些建议的解决方案(涉及列表的不同结构),我想在这里总结一下:
生活在未定义的行为中,因为该语言具有看似任意的限制,可以防止反向使用成员指针.
在其中存储指向包含类的附加指针IntrusiveListNode.这当前可能是最干净的解决方案(不需要更改接口),但确实需要在每个列表节点中使用第三个指针(可能有小的优化).
衍生IntrusiveListNode和使用static_cast.在boost中,这是base_hook一个侵入式链表的版本.我想坚持使用该member_hook版本以避免引入多重继承.
存储指向下一个和上一个包含类的指针,而不是指向其中的下一个和上一个列表节点IntrusiveListNode.这使得在侵入列表中创建根节点变得困难.列表必须包括完整的实例化T(这是不可能的,例如,如果T是抽象的),或者列表的末尾需要是空指针(它将中断--list.end(),仅允许前向迭代).
提升侵入列表有一个member_hook版本可以某种方式工作,但实现尚未被理解(它可能还依赖于未定义的行为). …
考虑以下:
typedef struct {
int a;
int b;
int c;
int d;
} ABCD;
typedef std::vector<ABCD> VecABCD;
Run Code Online (Sandbox Code Playgroud)
假设我想在VecABCD类型的向量中添加每个'a'成员.简单!我只是循环遍历向量,并在我去的时候求和.
int CalcSumOfA(const VecABCD &vec)
{
int sumOfA = 0;
VecABCD::const_iterator it;
for(it=vec.begin();it!=vec.end();it++)
sumOfA += it->a;
return sumOfA;
}
Run Code Online (Sandbox Code Playgroud)
说我想用'b'做同样的事情?简单!我写....基本上是相同的功能,但只有微不足道的变化.与'c'和'd'相同.
那么,有没有更简洁,更少重复的方式来做到这一点?我想做点什么:
int sumOfA = SumOfMembers(myVec, a);
Run Code Online (Sandbox Code Playgroud)
但我无法想象我如何将这样的功能放在一起.理想情况下,它是一个模板,我可以使用任何类型结构的向量,而不是专门绑定到VecABCD.有人有主意吗?
从这个问题开始,人们可以开始相信联盟的一致性不低于其个体成员的最大一致性.但我对long longgcc/g ++中的类型有问题.完整的示例可以在这里找到,但这里是我的问题的相关部分:
union ull {
long long m;
};
struct sll {
long long m;
};
int main() {
#define pr(v) cout << #v ": " << (v) << endl
pr(sizeof(long long));
pr(__alignof__(long long));
pr(sizeof(ull));
pr(__alignof__(ull));
pr(sizeof(sll));
pr(__alignof__(sll));
};
Run Code Online (Sandbox Code Playgroud)
这导致以下输出:
sizeof(long long): 8
__alignof__(long long): 8
sizeof(ull): 8
__alignof__(ull): 4
sizeof(sll): 8
__alignof__(sll): 4
Run Code Online (Sandbox Code Playgroud)
为什么union成员的对齐大于包含union的对齐?
[UPDATE]
根据基思的回答,对齐在这里是错误的.但我测试了以下内容,似乎alignof 告诉我们真实情况.看到:
union ull {
long long m;
};
long long a;
char b; …Run Code Online (Sandbox Code Playgroud) 我在过去5年的工作中假设虚拟继承打破了静态组合.
但是现在我发现,静态组合仍然保持不变,只有关于正确实例位置的附加信息.这是正确的吗?
也就是说,编译器用来生成类的标准是什么?例如,让我们说,我有类C与成员x,y以及z,我想知道的偏移z该类中.我可以只添加其他成员的数据类型大小,就像我对结构一样吗?
当编译器看到这段代码时:
SomeClass foo;
int x = foo.bar;
Run Code Online (Sandbox Code Playgroud)
检索bar值的过程是什么?即它看一些表示类定义的数据结构?如果是这样的数据结构是在编译时还是在运行时生成的?
这是代码片段
#include <iostream>
struct Z
{
Z():x(0),y(0),z(x){}
~Z(){}
int x;
int y;
int &z; // Reference member
};
template <typename Type, typename C, typename M>
size_t Offsetof (M C::* ptr_to_member)
{
Type type;
return reinterpret_cast<char*> (&(type.*ptr_to_member)) - reinterpret_cast<char*> (&type);
}
int main()
{
std::cout << Offsetof<Z>(&Z::x); // works
std::cout << Offsetof<Z>(&Z::y); // works
std::cout << Offsetof<Z>(&Z::z); // doesn't work
}
Run Code Online (Sandbox Code Playgroud)
我们无法创建指向引用的指针,因此该函数Offsetof不起作用z.
有没有办法为非POD取得参考数据成员的偏移量?