11

標準のレイアウトメンバー変数にpoinerが提供されている場合、その変数のオフセットを取得したいと思います。offsetof名前ではなくポインタを持っているので使えません。私が持っている現在のコードはこのように見えます、そして私はdummy変数を取り除くための標準に準拠した方法があるかどうか疑問に思っています。

template<class T>
struct {
  ptrdiff_t get_offset( int (T::*mem) )
  {
    T dummy;
    return reinterpret_cast<char*>(&(dummy.*mem)) 
      - reinterpret_cast<char*>(&dummy);
  }
};

intこの関数は、メンバー変数ポイントでのみ呼び出すことができます(これは意図的なものです)。

コンパイラーが実際にdummy変数を作成しないことは確かですが、それを取り除くことができればそれでもいいでしょう。nullの逆参照が定義されていないため、nullポインターを使用できません(ただし、おそらくすべての一般的なコンパイラーで機能します)。C ++ 03ソリュ​​ーションが適切であるか、C ++ 11ソリューションも重要です(ただし、現在は使用できません)。

注:これは標準に準拠しているだけであり、Tは標準のレイアウトタイプであることをすでに認識しています。

4

3 に答える 3

9

どうですか:

template<class T>
struct {
  ptrdiff_t get_offset( int (T::*mem) )
  {
    union {
      int used;
      T unused;
    } dummy;
    return reinterpret_cast<char*>(&(dummy.unused.*mem)) 
      - reinterpret_cast<char*>(&dummy.unused);
  }
};

ユニオン メンバーのアドレスは、構築されるユニオン メンバーに依存しません。C++03 では既に動作しますが、その後は POD でのみ動作します。

于 2012-08-27T14:43:24.640 に答える
2

OP要件を満たす標準準拠のソリューションは存在しないのではないかと思います。

準拠していないものをいくつかあげることができます。

template<class T>
  size_t get_offset( int (T::*mem) )
    {
    return reinterpret_cast<char*>(&(((T*)nullptr)->*mem))-reinterpret_cast<char*>(nullptr);
    }

おもしろいですが、VC2010ではoffsetofマクロであることを生かして以下が機能します。

template<class T>
  size_t get_offset( int (T::*mem) )
    {
    return offsetof(T, *mem);
    }
于 2012-08-27T12:06:02.450 に答える
1

それではどうですか:

template<class T>
struct {
    ptrdiff_t get_offset( int (T::*mem) )
    {
        return 
        ( &reinterpret_cast<const char&>( 
            reinterpret_cast<const T*>( 1 )->*mem ) 
          - reinterpret_cast<const char*>( 1 )      );
    }
};

..?

これにより、ダミーの使用と null の参照解除の両方が回避されます。私が試したすべてのコンパイラで動作します。(アドレスを取得してから char ポインターにキャストするのではなく) char 参照にキャストしてからアドレスを取得するのは珍しいように思えるかもしれませんが、一部のコンパイラでは警告/エラーを回避できます。

于 2016-11-30T07:32:48.603 に答える