Jun*_*uan 15 c++ templates metaprogramming member offset
给定C++中的类定义
class A
{
public:
//methods definition
....
private:
int i;
char *str;
....
}
Run Code Online (Sandbox Code Playgroud)
是否可以使用C++模板元编程在编译时计算类成员的偏移量?该类不是POD,并且可以具有虚方法,原始数据和对象数据成员.
Gle*_*Low 10
基于Matthieu M.的答案但更短且没有宏:
template<typename T, typename U> constexpr size_t offsetOf(U T::*member)
{
return (char*)&((T*)nullptr->*member) - (char*)nullptr;
}
Run Code Online (Sandbox Code Playgroud)
它被称为这样:
struct X { int a, b, c, d; }
std::cout << "offset of c in X == " << offsetOf(&X::c);
Run Code Online (Sandbox Code Playgroud)
编辑:
杰森赖斯是对的.这不会在C++ 11中产生实际的常量表达式.鉴于http://en.cppreference.com/w/cpp/language/constant_expression中的限制,它看起来不可能- 特别是没有指针差异,并且reinterpret_cast可以在常量表达式中.
嗯...在C ++ 11中,您实际上可以使用常规C ++工具来计算此类偏移量(即,无需委派给特定的编译器固有函数)。
在实际工作空间中:
template <typename T, typename U>
constexpr int func(T const& t, U T::* a) {
return (char const*)&t - (char const*)&(t.*a);
}
Run Code Online (Sandbox Code Playgroud)
但是,这里依赖于t对constexpr实例的引用,这可能不适用于所有类。只要它是构造函数,它就不会禁止T使用virtual方法,甚至构造constexpr函数。
尽管如此,这仍然是一个障碍。在未评估的上下文中,我们实际上可以std::declval<T>()用来模拟拥有一个对象。一无所有。因此,这对对象的构造函数没有特殊要求。另一方面,我们可以从这样的上下文中提取的值很少...而且它们的确也对当前的编译器造成了问题。
在实际工作空间中:
template <typename T, typename U>
constexpr size_t offsetof_impl(T const* t, U T::* a) {
return (char const*)t - (char const*)&(t->*a) >= 0 ?
(char const*)t - (char const*)&(t->*a) :
(char const*)&(t->*a) - (char const*)t;
}
#define offsetof(Type_, Attr_) \
offsetof_impl((Type_ const*)nullptr, &Type_::Attr_)
Run Code Online (Sandbox Code Playgroud)
我预见的唯一问题是virtual继承,因为它在基础对象上的运行时位置。如果存在其他缺陷,我将很高兴。
不,一般来说不是。
offsetof 宏存在于 POD(普通旧数据)结构中,并且可以使用 C++0x 将其稍微扩展为标准布局结构(或其他类似的轻微扩展)。因此,对于那些受限的情况,您有一个解决方案。
C++ 为编译器编写者提供了很大的自由。我不知道有任何子句可以阻止某些类对类的成员具有变量偏移量——但是,我也不确定为什么编译器会这样做。;)
现在,保持代码标准兼容但仍具有偏移量的一种方法是将数据粘贴到 POD(或某些 C++0x 扩展)子结构中,offsetof 将在该子结构上工作,然后处理该子结构struct 而不是整个类。或者您可以放弃标准合规性。类中结构体的偏移量是未知的,但结构体中成员的偏移量是未知的。
一个重要的问题是“我为什么想要这个,我真的有充分的理由吗”?