3

我想要做的是让一个类知道它在封闭类中的偏移量,而根本没有运行时开销。这是我希望我能做的一个例子:

template<int offset>
struct Inner {
};

struct Outer {
   int placeholder;
   Inner<offsetof(Outer, ptr)> ptr; 
};

上面的代码无法编译,因为offsetof(Outer, ptr)不知道ptr(它正在帮助定义它)。我已经实现了相同想法的几个版本,它们确实会产生运行时开销(在内存和执行指令中),但是我在实现“0 运行时开销”版本时遇到了麻烦,就像我上面的梦想实现一样。任何想法如何做到这一点?

4

2 回答 2

1
  1. 只有外部类型才能知道内部成员子对象的偏移量
  2. 因此成员子对象类型需要知道外部类型
  3. 幸运的是,这种事情经常出现。事实上,它重复出现的频率可以被认为是……好奇。
  4. 不幸的是,没有人为它想出一个好名字。因此,它被称为奇怪重复模板模式或简称 CRTP。

困难的是找出一种方法让外部类型自动生成内部偏移量,而不必手动编写每个偏移量。手工操作很容易,但很乏味,例如。

// use an enum to create distinct types
template<typename Outer, typename Outer::FieldId ID>
struct Inner
{
    static constexpr size_t offset();
};

struct Outer
{
    enum FieldId { First, Second };

    int header;
    Inner<Outer, FieldId::First> first;
    double interstitial;
    Inner<Outer, FieldId::Second> second;

    static constexpr size_t offset_of(std::integral_constant<FieldId, FieldId::First>) { return offsetof(Outer, first); }
    static constexpr size_t offset_of(std::integral_constant<FieldId, FieldId::Second>) { return offsetof(Outer, second); }
};

template<typename Outer, typename Outer::FieldId ID>
constexpr size_t Inner<Outer, ID>::offset()
{
    return Outer::offset_of(std::integral_constant<decltype(ID), ID> {});
}

这很笨拙,部分原因是std::integral_constant包装器(可以避免或 typedef'd),但主要是因为 ID 到字段的映射必须在代码中手动表示。

如果没有编译时反射,自动化生产很难。如果您只在顶层使用类似元组的对象而不是结构,则可以自动化所有事情,但这使得交错“智能”和愚蠢的成员变得更加困难,并且可能会更改布局,而且它肯定会违反StandardLayoutType要求,这可能会阻止offsetof完全工作。

于 2019-12-17T21:07:22.553 回答
0

可以通过代码重复和许多样板断言来模拟丑陋的方式:声明具有相同布局的“模板”类,声明目标类,编译时断言相应字段具有相同的偏移量。

struct OuterTemplate {
   int placeholder;
   Inner<0> ptr; 
};

struct Outer {
   int placeholder;
   Inner<offsetof(OuterTemplate, ptr)> ptr; 
};

static_assert(offsetof(OuterTemplate, ptr) == offsetof(Outer, ptr), 
              "Same offsetof assumption is not working");
于 2019-12-17T18:05:53.170 回答