从没有临时实例的成员指针偏移

时间:2012-08-27 11:52:07

标签: c++

我希望在为该变量提供一个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(尽管它可能适用于所有常见的编译器)。 C ++ 03解决方案会很好,或者C ++ 11解决方案也很有用(但现在我不能使用)。

注意:我已经知道这只是符合标准的,T是标准布局类型。

3 个答案:

答案 0 :(得分:8)

怎么样:

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

union成员的地址不依赖于正在构造的union成员。已经在C ++ 03中工作,但仅适用于POD。

答案 1 :(得分: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);
    }

答案 2 :(得分: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 )      );
    }
};

...

这避免了使用虚拟AND解除引用null。它适用于我尝试过的所有编译器。转换为char引用然后获取地址(而不是获取地址然后转换为char指针)可能看起来不寻常,但它避免了某些编译器的警告/错误。