C++ C++;模板内部的编译时偏移量

C++ C++;模板内部的编译时偏移量,c++,c++11,typetraits,offsetof,C++,C++11,Typetraits,Offsetof,我需要使用带有成员选择器的模板中的offset of。我想出了一个办法,请原谅我的语法有点笨拙: template <typename T, typename R, R T::*M > constexpr std::size_t offset_of() { return reinterpret_cast<std::size_t>(&(((T*)0)->*M)); }; 明显的缺点是它不是在编

我需要使用带有成员选择器的
模板中的
offset of
。我想出了一个办法,请原谅我的语法有点笨拙:

template <typename T,
          typename R,
          R T::*M
         >
constexpr std::size_t offset_of()
{
    return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
明显的缺点是它不是在编译时完成的(但更易于使用):

intmain()
{
std::cout以下内容应该有效(该想法的学分为):

正如Luc Danton所指出的,根据C++11标准,常量表达式不能包含
reinterpret\u cast
,尽管目前gcc接受该代码(参见)。此外,我发现
谈到降低规则的严格程度,因此将来可能会发生变化。

我试图找出标准中的哪些地方说这符合您的期望。但我找不到它。标准有什么问题?@Nicolas我想没有。取消对
nullptr的引用不应该吗
(我认为
->
算作取消引用)已经是UB了吗?但是,VC版本的
offsetof
宏没有任何不同。因此在实践中,它可能是实现定义的而不是未定义的。@ChristianRau如果标准不要求实现来记录其支持,则支持不是实现定义的。在这种情况下,如果实现定义了行为(我并不是说VC有),它只是一个允许的扩展。未定义行为的一个有效结果就是完全按照您的意愿行事。@Joachim Pileborg:
offsetof
仅适用于成员名称,而不适用于
mt:*
。常量表达式不能包含
重新解释转换(除非未计算)@LucDanton:谢谢你提供的信息。我还找到了一个关于放宽限制的方法。我一直在尝试修改此方法,以允许的OFFSET_接受指向成员的指针,但没有成功()-有人知道这是否可能吗?这使得它更加严格,但两者都在常量表达式中使用
重新解释\u cast
。所以您认为您的代码不会调用未定义的行为?
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), "");
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;
}
#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, "");
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)