11

当提供指向该变量的指针时,我想获得标准布局成员变量的偏移量。我不能使用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 是标准布局类型。

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 回答