【问题标题】:Coerce pointer to member to most derived type将指向成员的指针强制为大多数派生类型
【发布时间】:2015-06-12 14:59:06
【问题描述】:

考虑这种类型层次结构:

struct A {
    int x;
};

struct B : A {
    int y;
};

&B::y 的类型是int B::*,但&B::x 的类型是int A::*。它可以转换为int B::*,这是我需要的,但我需要显式执行该转换。

有没有一种方便的方法可以将类型推断为指向我指定的类的成员的指针?毕竟,如果我想要A::*x,我可以做到&A::x

【问题讨论】:

  • 一种“方便的方式”?上下文是什么?像bikeshed<B>([](auto wrapper){ return &unwrap<decltype(wrapper)>::x; }) 这样的奇怪表达方便吗?编辑:哎呀,那是 C++14
  • @dyp 只是想避免写template <typename Derived, typename CLS, typename T> T Derived::* to_derived(T CLS::*member) 之类的东西,因为当B 的名称很长时,to_derived<B>(&B::x) 的输入有点烦人。只是希望我错过了一些聪明的方法。
  • 你可以尝试推导非多态lambda的operator()的参数类型,那么bikeshed([](tag<B> d){ return &unwrap<decltype(d)>::x })是可能的。如果只有一小部分成员名称,例如x,当然可以使用bikeshed<B>(x_name) 来作为一些帮助对象x_name
  • 您仍然可以使用 #define member_ptr(C, m) to_derived<C>(&C::m) 缩短它。
  • @Jarod42 是的,这就是我最终的结果。看起来像类型系统的一个奇怪方面不是吗?

标签: c++ c++11 pointer-to-member


【解决方案1】:

在虚拟继承的情况下,这种转换是不可能的。假设

struct A {
  int x;
};

struct B : virtual A {
  int y;
};

还有两个函数,

int f(B* pB) {
  int A::*pX = &A::x; // or &B::x, identical but clearer this way
  return pB->*pX;
}

int g(B* pB) {
  int B::*pY = &B::y;
  return pB->*pY;
}

f(B*) 需要进行 vtable 查找,以便在 *pB 中找到 A 实例的基指针,而 g(B*) 仅对 pB 应用偏移量。因此对象&A::x 不能表示为int B::* 类型的实例,它需要一个不同的运行时逻辑来使用指向B 的指针而不是int B::*

即使B 是此时此地派生度最高的类,也可以定义另一个类C 继承AB 在不同的编译单元中 C*f()。所以AB内的偏移量不能被认为是固定的。

有人可能会争辩说,如果不存在虚拟继承,或者在匿名命名空间中,或者......但始终禁止它可能更容易。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 2021-12-03
    • 2017-03-09
    • 2020-10-01
    • 2016-10-10
    • 2017-07-18
    • 1970-01-01
    相关资源
    最近更新 更多