"Derived pointer to member" 到 "base pointer to member" 错误

"Derived pointer to member" to "base pointer to member" error

为了支持一些编译时魔法,我想使用指向成员的指针,例如:

struct BaseT
{
};

struct DerivedT: public BaseT
{
};

struct TestT 
{
    DerivedT testMem;

    typedef BaseT (TestT::* TestTMemPtr);

    constexpr TestT() = default;

    static constexpr TestTMemPtr testMemOffset()
    {
        return &TestT::testMem;
    }
};

int main()
{
    constexpr TestT test;
}

我不能 return 派生成员指针作为基成员指针,我用 clang 得到这个:

cannot initialize return object of type 'TestT::TestTMemPtr' (aka 'BaseT (TestT::*)') with an rvalue of type 'DerivedT TestT::*'

我用gcc检查了一下:

error: invalid conversion from 'DerivedT TestT::*' to 'TestT::TestTMemPtr' {aka 'BaseT TestT::*'}

这是正常行为吗?我以为我总是可以使用派生指针作为基指针。

更新: 好吧,原来的例子不是最好的,我觉得这个更有表现力,所以 DerivedT* 可以用作 BaseT*,但 DerivedT TestT::* 不能用作 BaseT TestT::* :

struct BaseT
{
};

struct DerivedT: public BaseT
{
};

struct TestT 
{
    DerivedT m_test;
};

using BaseTMemPtr = BaseT TestT::*;

int main()
{
    TestT test;
    BaseT* simplePtr = &test.m_test; //It is DerivedT*, but can be used as BaseT*
    BaseT (TestT::*memPtr) = &TestT::m_test; //Error, BaseT TestT::* cannot be used as DerivedT TestT::*
    BaseTMemPtr memPtr2 = &TestT::m_test; //Error, just the same
}

从继承的角度来看,BaseT TestT::*DerivedT TestT::*是两个不相关的类型¹,所以你不能从后者初始化前者,反之亦然,就像你不能用 double* 初始化 int* 因为 intdouble 不是基于和派生 classes.


¹ 我的意思是这些类型的两个对象不指向两个 classes,它们是另一个的基础。 BaseT TestT::*DerivedT TestT::* 都是指针类型,但它们不指向两个 class 中的一个是另一个的基础;它们甚至不首先指向 classes(请参见下面的演示代码),因此指向的类型之间不存在继承关系,因为继承是 [ 之间的事情=66=]es,一般不在类型之间,比如成员函数类型。

#include <type_traits>
struct BaseT {};

struct DerivedT: public BaseT {};

struct TestT {};

template<typename T, typename = void>
struct points_to_class : std::false_type {};
template<typename T>
struct points_to_class<T*> : std::is_class<T> {};

static_assert(points_to_class<BaseT*>::value); // passes
static_assert(points_to_class<BaseT TestT::*>::value); // fails

但是,指针之间的转换是否只有当它们都指向class时才有可能这两个class是通过继承相关的?

好吧,如果你看一下 Pointer declaration page on cppreference.com,它确实有一个关于 成员函数指针 的部分,它是关于成员指针之间的转换函数。

但是它是关于指向成员函数的基class指向指针的指针到派生的 class 的同一个成员函数 ,而您似乎正在寻找将 指针转换为成员函数(TestT) 返回一个基数class (BaseT)指向成员函数的指针相同的 class (TestT) 返回 派生的 class (DerivedT) .同样,这两种类型是无关的。