我需要使用offsetof
中的template
和成员选择器。如果您原谅尴尬的语法,我想出办法:
template <typename T,
typename R,
R T::*M
>
constexpr std::size_t offset_of()
{
return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
用法并不完美(最好烦恼):
struct S
{
int x;
int y;
};
static_assert(offset_of<S, int, &S::x>() == 0, "");
static_assert(offset_of<S, int, &S::y>() == sizeof(int), "");
非constexpr
表单更易于使用:
template <typename T, typename R>
std::size_t offset_of(R T::*M)
{
return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
明显的缺点是它不是在编译时完成的(但更容易使用):
int main()
{
std::cout << offset_of(&S::x) << std::endl;
std::cout << offset_of(&S::y) << std::endl;
}
我正在寻找的是语法,如非constexpr
种类,但仍然是完全编译时间;但是,我无法想出它的语法。我也很满意offset_of<&S::x>::value
(就像其他类型特征一样),但无法弄清楚它的语法魔法。
答案 0 :(得分:13)
以下内容应该有效(点数转到the answer to this question):
#include <cstddef>
template <typename T, typename M> M get_member_type(M T::*);
template <typename T, typename M> T get_class_type(M T::*);
template <typename T,
typename R,
R T::*M
>
constexpr std::size_t offset_of()
{
return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
}
#define OFFSET_OF(m) offset_of<decltype(get_class_type(m)), \
decltype(get_member_type(m)), m>()
struct S
{
int x;
int y;
};
static_assert(OFFSET_OF(&S::x) == 0, "");
请注意,在gcc中,offsetof
宏扩展为可在编译时使用的内置扩展(见下文)。此外,您的代码调用UB,它取消引用空指针,因此即使它可能在实践中起作用,也无法保证。
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
正如Luc Danton所指出的,根据C ++ 11标准,常量表达式不能涉及reinterpret_cast
,尽管当前gcc接受代码(参见bug report here)。另外,我找到了defect report 1384
谈到使规则不那么严格,所以这可能会在未来发生变化。