<分区>
下面的代码尝试在 C++11 中实现 offsetof
的 constexpr
版本。它在 gcc 7.2.0 和 clang 5.0.0 中编译。
这取决于将 std::addressof
应用于 union 体的非活跃成员的成员。
这是定义明确的 C++11 吗?如果不是,请解释原因,包括引用或引用标准的相关部分。
#include <iostream>
#include <cstdint>
#include <memory>
// based on the gist at: https://gist.github.com/graphitemaster/494f21190bb2c63c5516
// original version by graphitemaster
template <typename T1, typename T2>
struct offset_of_impl {
union U {
char c;
T1 m; // instance of type of member
T2 object;
constexpr U() : c(0) {} // make c the active member
};
static constexpr U u = {};
static constexpr std::ptrdiff_t offset(T1 T2::*member) {
// The following avoids use of reinterpret_cast, so is constexpr.
// The subtraction gives the correct offset because the union layout rules guarantee that all
// union members have the same starting address.
// On the other hand, it will break if object.*member is not aligned.
// Possible problem: it uses std::addressof on non-active union members.
// Please let us know at the gist if this is defined or undefined behavior.
return (std::addressof(offset_of_impl<T1, T2>::u.object.*member) -
std::addressof(offset_of_impl<T1, T2>::u.m)) * sizeof(T1);
}
};
template <typename T1, typename T2>
constexpr typename offset_of_impl<T1, T2>::U offset_of_impl<T1, T2>::u;
template <typename T1, typename T2>
inline constexpr std::ptrdiff_t offset_of(T1 T2::*member) {
return offset_of_impl<T1, T2>::offset(member);
}
struct S {
S(int a_, int b_, int c_) : a(a_), b(b_), c(c_) {}
S() = delete;
int a;
int b;
int c;
};
int main()
{
std::cout << offset_of(&S::b);
}
作为引用,这里有一个可以玩的沙盒版本:https://wandbox.org/permlink/rKQXopsltQ51VtEm
这是 graphitemaster 的原始版本: https://gist.github.com/graphitemaster/494f21190bb2c63c5516