これは、テンプレートではありませんが、offsetofマクロを用いるのが定石です。offsetofマクロは<cstddef>ヘッダで定義されますので、(組み込み用などの)自立処理系であっても、必ず提供されることが規格上保証されています(非標準処理系は別ですが)。
仮に、offsetofマクロを自作する必要がある場合、C言語では、
0 1 2 |
#define offsetof(type, member) ((size_t)&((type*)0)->member) |
とすれば十分でしたが、C++ではそうはいきません。なぜなら、&演算子が多重定義されている可能性があるからで、正しく動作させるためには、
0 1 2 3 4 5 |
#define offset_of(type, member) \ (reinterpret_cast<std::size_t>( \ &reinterpret_cast<char const volatile&>( \ ((type*)0)->member))) |
とする必要があります。
ところで、ここは「C++関数・テンプレート集」であってマクロ集ではないので、やや強引ですが、テンプレート版も作ってみましょう。
0 1 2 3 4 5 6 7 8 |
template<class T, class C> std::size_t offset_of(T (C::*pm)) { return reinterpret_cast<std::size_t>( &reinterpret_cast<const volatile char&>(((C*)0)->*pm) ); } |
引数としてメンバへのポインタを渡すことで、オフセットを返すoffset_of関数テンプレートです。定数式に展開することができないので、offsetofマクロにはどうしても劣りますが、テンプレートの中であれば、利用価値があるかもしれません。
なお、C++11以降であればstd::addressof関数が使えますので、次のように書いてもよいでしょう。
0 1 2 3 4 5 6 |
template<class T, class C> std::size_t offset_of(T (C::*pm)) { return (std::size_t)std::addressof(((C*)0)->*pm); } |
std::addressof関数を使うには<memory>をインクルードしてください。