我希望在为该变量提供一个poiner时获得标准布局成员变量的偏移量。我不能使用offsetof
,因为我有一个指针,而不是一个名字。我当前的代码看起来像这样,我想知道是否有符合标准的方法来摆脱dummy
变量。
template<class T>
struct {
ptrdiff_t get_offset( int (T::*mem) )
{
T dummy;
return reinterpret_cast<char*>(&(dummy.*mem))
- reinterpret_cast<char*>(&dummy);
}
};
此函数只能使用int
成员变量点进行调用(这是故意的)。
我很确定编译器实际上并没有创建dummy
变量,但如果我能摆脱它,它仍然会很好。我不能使用空指针,因为未定义解除引用null(尽管它可能适用于所有常见的编译器)。 C ++ 03解决方案会很好,或者C ++ 11解决方案也很有用(但现在我不能使用)。
注意:我已经知道这只是符合标准的,T是标准布局类型。
答案 0 :(得分:8)
怎么样:
template<class T>
struct {
ptrdiff_t get_offset( int (T::*mem) )
{
union {
int used;
T unused;
} dummy;
return reinterpret_cast<char*>(&(dummy.unused.*mem))
- reinterpret_cast<char*>(&dummy.unused);
}
};
union成员的地址不依赖于正在构造的union成员。已经在C ++ 03中工作,但仅适用于POD。
答案 1 :(得分:2)
我担心没有符合OP要求的符合标准的解决方案。
我可以提供一些不合规的。
template<class T>
size_t get_offset( int (T::*mem) )
{
return reinterpret_cast<char*>(&(((T*)nullptr)->*mem))-reinterpret_cast<char*>(nullptr);
}
这很有趣,但以下在VC2010中有效,使用offsetof
作为宏。
template<class T>
size_t get_offset( int (T::*mem) )
{
return offsetof(T, *mem);
}
答案 2 :(得分:1)
那怎么样:
template<class T>
struct {
ptrdiff_t get_offset( int (T::*mem) )
{
return
( &reinterpret_cast<const char&>(
reinterpret_cast<const T*>( 1 )->*mem )
- reinterpret_cast<const char*>( 1 ) );
}
};
...
这避免了使用虚拟AND解除引用null。它适用于我尝试过的所有编译器。转换为char引用然后获取地址(而不是获取地址然后转换为char指针)可能看起来不寻常,但它避免了某些编译器的警告/错误。