【问题标题】:Offset of pointer to member指向成员的指针的偏移量
【发布时间】:2011-08-02 19:13:08
【问题描述】:
template<class T, typename U> ptrdiff_t foo(T U::* m)
{
    // return offset
}

在这种情况下如何获取字段“m”的偏移量?我更喜欢使用 am 编译时表达式。

提前感谢您的帮助。最好的问候

【问题讨论】:

  • 这可能是个坏主意。为什么不使用指向成员的类型呢?
  • 哼,你到底是什么意思?上面的参数是一个指向成员的指针...
  • 好吧,就这样吧。偏移量太原始,无法用于大多数 C++ 类(非 POD)。
  • 好的,但是你已经写了'为什么不使用指向成员类型的指针 INSTEAD?你是什​​么意思?顺便说一句:我可以编写我的 member_offset 函数的编译器特定版本。
  • @GManNickG Vulkan、OpenGL 和任何其他使用结构化缓冲区的图形库都需要偏移量而不是指向成员的指针。在这种情况下,他们不理解指向成员的指针,您必须将其转换为偏移量。

标签: c++ templates member-pointers


【解决方案1】:

@迈克尔·J

感谢您的回答。这并不是我想要的,但它给了我这样做的灵感:

template<class T, typename U>
std::ptrdiff_t member_offset(U T::* member)
{
    return reinterpret_cast<std::ptrdiff_t>(
        &(reinterpret_cast<T const volatile*>(NULL)->*member)
    );
}

【讨论】:

  • 您在此处取消引用空指针。这是不允许的,除非您正在实现该库并获得在 offsetof 宏中使用的特殊规定。有人把我打到-1。
  • 这就是 offsetof 宏的作用:(size_t)&reinterpret_cast((((s *)0)->m))。有什么区别?
  • 不同之处在于 offsetof 为 特定编译器 执行此操作,只是因为库设计者与编译器编写者做了特殊处理。那么它可能会起作用。在其他编译器上,offsetof 用作特殊的 __builtin_offsetof 函数。或者其他什么技巧。库中有offsetof的主要原因是不能移植,需要编译器的特殊支持。
  • 就像我在上面的评论中所说,offsetof 和 kin 在 C++ 中是个坏主意。使用指向成员的指针。
【解决方案2】:

听起来您正在寻找 offsetof() 宏。

【讨论】:

  • 用成员指针调用offsetof是不合法的,只有成员名。 (在许多实现中它可能会起作用,但鉴于这种事情是多么晦涩难懂,它可能会破坏任何编译器更新)
  • 嗨@Yakk。我不太清楚你的意思。如果您单击“offsetof”(上图)这个词,它会将您带到宏的文档。对我来说它看起来很犹太。对您的“成员指针”是指作为指针的结构的成员?例如结构 s { int i;字符 *p; }; size_t n = offsetof(struct s, p);
【解决方案3】:

简单的答案是你不能。如果 U 型是 POD, 你可以使用宏offsetof,但形式上它是未定义的 如果类型不是 POD 时的行为:取决于编译器, 你会得到一个编译时错误,或者只是一些错误的结果 时间。而且您不能在指向成员的指针上使用它。你 必须使用类的名称和名称来调用它 成员。

【讨论】:

    【解决方案4】:

    可以获得偏移量,但它不是免费的:

    template <typename T, class C>
    size_t memberOffset(T C::*member)
    {
        C c {};
        return size_t(&(c.*member)) - size_t(&c);
    }
    
    // usage
    struct Vector {
        int x;
        int y;
    };
    
    size_t off = memberOffset(&Vector::y);
    

    不幸的是,正如您所见,这不是constexpr,因此它不能用于您可能想要的所有场景。它也有(非常小的)开销,但编译器似乎只是完全优化了它:https://godbolt.org/z/jGeox9

    如果您想知道是否可以自己将constexpr 洒在任何地方并使其工作,您可以,并且您的编译器甚至可以编译并运行它,但是对size_t 使用强制转换在@987654327 中无效@尽管存在许多编译器允许的已知缺陷。

    这种方法的功劳不属于我,而是 Daniel Weiler 和这个优秀的要点:https://gist.github.com/graphitemaster/494f21190bb2c63c5516

    【讨论】:

      猜你喜欢
      • 2012-02-22
      • 2019-06-23
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-09
      • 2013-05-02
      相关资源
      最近更新 更多