constexprでメンバ変数のオフセットを取得する
constexpr
でも頑張ればメンバオフセットを取得できるみたいです。constexpr
版offsetof
ですね
コードはこのGithubでの議論あたりを参考にしました。
コンパイルにはc++17
が必要です
gcc 7.0
/ clang 6.0
あたりでコンパイルできます。
msvc
は VS2017 15.8 Preview 3
からコンパイルできようになりました。やったね!
template <typename T1, typename T2> struct offset_of_member_impl { union U { U() : c{} {} ~U() {} char c[sizeof(T2)]; T2 o; }; static U u; static constexpr size_t get(T1 T2::*member) { size_t i = 0; for (; i < sizeof(T2); ++i) if (((void*)&(u.c[i])) == &(u.o.*member)) break; // g++ bug 67371 workaround if (i >= sizeof(T2)) throw std::runtime_error("failed to detect offset"); else return i; } }; // suppress warning template <class T1, class T2> typename offset_of_member_impl<T1, T2>::U offset_of_member_impl<T1, T2>::u{}; /// get offset of member template <class T1, class T2> constexpr size_t offset_of_member(T1 T2::*member) { return offset_of_member_impl<T1, T2>::get(member); }
g++のバグを回避するためにループをばらしています。
こんな感じで使います
struct A { int i; char c; double d; }; int main() { constexpr size_t offi = offset_of_member(&A::i); constexpr size_t offc = offset_of_member(&A::c); constexpr size_t offd = offset_of_member(&A::d); std::cout << offi << std::endl; //0 std::cout << offc << std::endl; //4 std::cout << offd << std::endl; //8 }