2012-10-10 19 views
14

メンバーセレクタでtemplateoffsetofを使用する必要があります。あなたは厄介な構文を失礼場合、私は、道を作ってみた:C++テンプレート内のコンパイル時のオフセット

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(他のタイプの特徴と同様)にも満足していますが、そのための構文マジックを理解することはできません。 gccのでは、offsetofマクロが(下記参照)、コンパイル時に使用することができ、組み込み拡張子に展開することを

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

注:

+0

私は、標準で、これがあなたが期待していることをしていると言っているところを理解しようとしています。しかし、私はそれを見つけることができません。 –

+4

標準の['offsetof'](http://en.cppreference.com/w/cpp/types/offsetof)には何の問題がありますか? –

+0

@NicolBolas私はそうは思わない。 'nullptr'の逆参照ではないはずです(そして' - > 'は逆参照とみなされます)はすでにUBですか?しかし、やはり、VCの 'offsetof'マクロのバージョンはそれほど変わっていません。したがって、実際には、おそらく定義されていないよりもむしろ実装が定義されています。 –

答えて

13

次は動作するはずです(クレジットはアイデアのためにthe answer to this questionに行きます)。また、あなたのコードはUBを呼び出し、それはヌルポインタをデリファレンスします。したがって、実際に動作しても、保証はありません。

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

としてリュックダントンによって指摘現在GCCコードを受け付けているが、定数式は、C++ 11標準に従ってreinterpret_castを含むことができない(bug report hereを参照)。また、私はdefect report 1384を見つけました。これは、規則をあまり厳しくしないことについて、 が話しているので、将来変更する可能性があります。

+0

それでは、よく見えます。 – hvd

+4

定数式は(評価されない限り) 'reinterpret_cast'を含むことはできません。 –

+1

@LucDanton:情報をありがとう。私はまた、[不具合報告書1384](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1384)に、その制限を緩めることについて話しました。 –

関連する問題