【问题标题】:constexpr Offsetof with pointer to member data带有指向成员数据的指针的 constexpr Offsetof
【发布时间】:2018-10-09 08:54:24
【问题描述】:

就在此问题因重复而被驳回之前,大多数(如果不是全部)问题已经接受了带有过时/未定义行为解决方案的答案。

问题:

有没有办法在编译时获取指向成员数据的指针的偏移量:

  • 不依赖未定义的行为(nullptr 事物)
  • 适用于最新的 gcc 版本(编译器资源管理器中的 gcc trunk
  • 工作方式与offsetof 相同(或类似地,就像提议的代码一样)。

我不在乎:

  • 非标准布局类型
  • msvc 兼容性。 (这可能很好,但可选)
  • 具有特定编译器的特殊情况

问题:

使用 GCC 的主干版本,以下技巧(hack)不起作用:

#include <cstdint>
#include <cstddef>

namespace detail
{
    // The union stuff is for CLang to avoid creating warnings
    template<typename T, auto MPtr>
    struct offsetof_ptr_helper
    {
        union helper_t { int i = 0;  T value; };
        static constexpr helper_t v = {};
        static constexpr size_t sz = sizeof
        (uint8_t[
            (uint8_t *)&(v.value.*MPtr) -
            (uint8_t *)&v.value
        ]);
    };
}

template<typename T, auto MPtr>
static constexpr size_t offsetof_ptr()
{
    return detail::offsetofptr_helper<T, MPtr>::sz;
}

size_t f()
{
    struct X { char c[10]; int a; };
    return offsetof_ptr<X, &X::a>();
}

需要明确的是,这是一个使用 C++98 特性的 hack,最新的编译器正在删除它的支持也就不足为奇了。它适用于 clang(使用 -std=gnu++17 标志)和 gcc(包括/up-to g++ 7.3,使用标志 -std=c++17)。

【问题讨论】:

标签: c++


【解决方案1】:

如果你跳转到 VS 中offsetof 的定义,它会给你这个:

#define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))

修改了一下以匹配您的问题:

template<typename T, auto MPtr>
static constexpr size_t offsetof_ptr()
{
    return ((::size_t) & reinterpret_cast<char const volatile&>((((T*)0)->*MPtr)));
}

size_t f()
{
    struct X { char c[10]; int a; };
    return offsetof_ptr<X, &X::a>();
}

这在 GCC 和 MSVC 上编译。 (由于模板自动参数,它需要 C++17。)

【讨论】:

  • 我认为 OP 正在寻找真正的 constexpr 版本。尽管你已经标记了你的函数constexpr,但它不是一个常量表达式,因为它取消引用一个空指针(未定义的行为),参见例如here.
  • 哦,对了,OP 还说他不想要 nullptr 的东西。我认为如果这对编译器来说足够好,那么对其他人来说可能已经足够好了?
  • 对于那个编译器来说已经足够好了,但是由于它是未定义的行为,它可能无法像其他编译器那样工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 2016-08-11
相关资源
最近更新 更多