【问题标题】:Passing the offset of a field as a template parameter to that field将字段的偏移量作为模板参数传递给该字段
【发布时间】:2020-04-10 05:39:56
【问题描述】:

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

template<int offset>
struct Inner {
};

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

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

【问题讨论】:

  • 在课程完成之前,您无法知道课程的布局是什么,所以我不确定您可以做些什么来实现零运行时间成本。不确定一旦我们得到反射是否会有所帮助。这有什么用例?
  • 我将其用于在计算机体系结构研究中跟踪访问的特定方法,因此其他方法在上下文中不起作用。虽然是的,但在类完成之前无法知道布局,但我确信有一些编译时解决方法 - 可能是某种包装类或其他东西。我只是想不出来:(
  • 如果Inner 的大小是固定的,那么Outer 的布局无法计算的根本原因。我同意我的梦想方法行不通,但我真的希望有某种解决方法,因为我认为没有什么实际上阻止它(以某种方式)起作用。
  • “如果Inner的大小是固定的”。一般情况下很难知道(可能有专业化)。
  • @antonin_salia Inner 的大小无关紧要。它的对齐方式可以。如果您可以保证Inner 的固定对齐方式,例如alignas(X),那么无论Inner 内部可能是什么,它在Outer 内的偏移量都是固定的(至少实际上;理论上,编译器可以插入填充为他们希望,但实际上他们这样做只是为了对齐)。

标签: c++ templates offset offsetof


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

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

// 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 完全正常工作。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 有趣...试图弄清楚如何使用宏或其他东西自动执行此操作
    猜你喜欢
    • 2012-03-02
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 2013-05-26
    相关资源
    最近更新 更多