【问题标题】:Why is it not allowed to cast Derived T::* to Base T::*?为什么不允许将 Derived T::* 转换为 Base T::*?
【发布时间】:2014-12-07 22:10:58
【问题描述】:

背景:许多函数式语言都支持代数数据类型,这在一定程度上可以用虚函数和继承来模拟。

最明显的解决方案涉及堆分配,因为派生类型进入 不同的尺寸。但是,我们应该能够使用联合来保存堆栈上最大的类型,而无需任何额外的分配。这需要一个额外的指向基址的指针与联合一起存储,同时使复制和赋值复杂化。

通过将成员选择器存储为从指向活动联合成员的联合开始的偏移量来解决后一个问题是很有说服力的。 C++ 的成员指针似乎几乎适合此目的,只是指向每个成员的指针将具有不同的类型。

问题:为什么不允许将 Derived T::* 转换为 Base T::*?

这是一个与上述无关的玩具示例,它遇到了相同的限制:

struct fish {};
struct shark : public fish {};
struct trout : public fish {};

struct aquarium
{
    shark shark;
    trout trout;
};

fish aquarium::* pick_dinner(bool dangerous = true)
{
    if (dangerous)
    {
        return &aquarium::shark;
    }
    return &aquarium::trout;
}

#include <iostream>

void cook(fish&)
{
    std::cerr << "Do it yourself\n";
}

int main()
{
    aquarium spherical, hexagonal;
    fish aquarium::*ingredient = pick_dinner();
    cook(spherical.*ingredient);
    cook(hexagonal.*ingredient);
}

生成的编译错误:

main.cpp:15:16: error: cannot initialize return object of type 'fish aquarium::*' with an rvalue of type 'shark aquarium::*'
        return &aquarium::shark;
               ^~~~~~~~~~~~~~~~
main.cpp:17:12: error: cannot initialize return object of type 'fish aquarium::*' with an rvalue of type 'trout aquarium::*'
    return &aquarium::trout;
           ^~~~~~~~~~~~~~~~
2 errors generated.

【问题讨论】:

  • 您可以尝试将&amp;aquarium::shark&amp;aquarium::trout 显式转换为fish *,然后?: 的第二个和第三个参数将是相同的类型。
  • 你试过if(dangerous) return &amp;aquarium::shark; else return &amp;aquarium::trout 吗?
  • 使用成员指针的全部目的是不引用特定的实例。这变得很重要,尤其是在为 union+selector 组合实现复制和赋值构造函数时。
  • 至于你的第二个表扬,CiaPan,那不会有任何区别。
  • 我不明白你为什么不直接从 pick_dinner() 返回 Fish* 并将 ingredient 变成 Fish*

标签: c++ member-pointers pointer-conversion


【解决方案1】:

为什么不允许将Derived T::* 转换为Base T::*

因为语言标准不允许这样做。除了空成员指针转换之外,唯一允许的指向成员转换的指​​针是类型<em>cv</em> T Base::*<em>cv</em> T Derived::* 的转换,如标准部分4.11/2 所述。

我不知道它的确切原因,但对应的Core language issue 794rejected,因为“在标准化过程的这一点上没有达成共识”。 Recent activity 在这个问题上表示它可能会在下一个 C++ 标准(C++17)中发生变化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    • 2017-03-19
    • 2010-11-01
    相关资源
    最近更新 更多