C++ 为什么不允许将派生的T::*强制转换为基T::*?

C++ 为什么不允许将派生的T::*强制转换为基T::*?,c++,member-pointers,pointer-conversion,C++,Member Pointers,Pointer Conversion,背景:许多函数式语言支持代数数据类型,在一定程度上可以通过虚拟函数和继承来模拟这些数据类型 最明显的解决方案涉及到堆分配,因为派生类型会出现 大小不一。但是,我们应该能够使用联合来保存堆栈上最大的类型,而不需要任何额外的分配。这需要一个指向base的附加指针与union一起存储,同时使复制和赋值复杂化 通过将成员选择器存储为指向活动联合成员的联合起点的偏移量来解决后一个问题是很有必要的。C++中的成员指针看起来几乎符合目的,除了指向每个成员的指针将有不同的类型。 问题:为什么不允许将派生的T::

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

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

通过将成员选择器存储为指向活动联合成员的联合起点的偏移量来解决后一个问题是很有必要的。C++中的成员指针看起来几乎符合目的,除了指向每个成员的指针将有不同的类型。 问题:为什么不允许将派生的T::*强制转换为基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);
}
为什么不允许将
派生的T::*
强制转换为
基T::*

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


我不知道确切的原因,但相应的原因是“在标准化过程中的这一点上,没有达成一致意见来进行此更改”。这个问题表明,它可能会在下一个C++标准中发生变化。

你可以尝试“C++”和“鱼缸”的显式转换:鲨鱼>代码> <代码>鱼缸::鳟鱼<代码> >代码>鱼*<代码>,那么第二个和第三个参数<代码>:< /> >将是相同的类型。你尝试过<代码>(危险)返回和水族馆::鲨鱼;else return&Oquarium::trout?使用成员指针的全部目的是不引用特定实例。这一点非常重要,尤其是在为union+选择器组合实现复制和赋值构造函数时。至于你的第二个推荐词CiaPan,这不会有任何区别。我不明白为什么你不从
pick_Diner()
返回一条
鱼*
,然后制作
配料
一条
鱼*
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.