C++ Compile-Time offsetof模板内部

Tra*_*kel 14 c++ offsetof type-traits c++11

我需要使用offsetoftemplate一个成员选择.如果您原谅尴尬的语法,我想出办法:

template <typename T,
          typename R,
          R T::*M
         >
constexpr std::size_t offset_of()
{
    return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
Run Code Online (Sandbox Code Playgroud)

用法并不完美(最好烦恼):

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), "");
Run Code Online (Sandbox Code Playgroud)

constexpr形式更容易使用:

template <typename T, typename R>
std::size_t offset_of(R T::*M)
{
    return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
Run Code Online (Sandbox Code Playgroud)

明显的缺点是它不是在编译时完成的(但更容易使用):

int main()
{
    std::cout << offset_of(&S::x) << std::endl;
    std::cout << offset_of(&S::y) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是语法constexpr品种,但仍然完全编译时间; 但是,我无法想出它的语法.我也很满意offset_of<&S::x>::value(就像其他类型特征一样),但无法弄清楚它的语法魔法.

Jes*_*ood 13

以下应该工作(学分转到这个问题的答案):

#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, "");
Run Code Online (Sandbox Code Playgroud)

请注意,在gcc中,offsetof宏扩展为内置扩展,可以在编译时使用(参见下文).此外,您的代码调用UB,它取消引用空指针,所以即使它可能在实践中工作,也没有保证.

#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
Run Code Online (Sandbox Code Playgroud)

正如Luc Danton指出的那样,常量表达式不能涉及reinterpret_cast根据C++ 11标准,尽管当前gcc接受代码(请参阅此处错误报告).此外,我发现了缺陷报告1384,其中谈到了使规则不那么严格,因此将来可能会发生变化.

  • 常量表达式不能涉及`reinterpret_cast`(除非未评估). (4认同)