18

メンバーセレクターでoffsetofから使用する必要があります。template厄介な構文を許せば、私は方法を考え出しました:

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

使用法は完璧ではありません(せいぜい迷惑です):

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), "");

constexprフォームの方が使いやすいです。

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;
}

私が探しているのは、非多様性のようなconstexpr構文ですが、それでも完全にコンパイル時です。ただし、その構文を思い付くことができません。(他のタイプの特性と同様に)私も満足しますがoffset_of<&S::x>::value、その構文の魔法を理解することはできません。

4

1 に答える 1

18

以下が機能するはずです(クレジットはアイデアのこの質問への回答になります):

#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, "");

gccでは、offsetofマクロはコンパイル時に使用できる組み込みの拡張機能に展開されることに注意してください(以下を参照)。また、コードはUBを呼び出し、nullポインターを逆参照するため、実際に機能する場合でも、保証はありません。

#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)

Luc Dantonが指摘しているようreinterpret_castに、現在gccはコードを受け入れますが、定数式はC ++ 11標準に従ってを含むことはできません(ここのバグレポートを参照してください)。また、ルールの厳格さを緩和することについて説明している欠陥レポート1384を見つけたので、これは将来変更される可能性があります。

于 2012-10-10T05:00:38.450 に答える