"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*
因为 int
和 double
不是基于和派生 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
) .同样,这两种类型是无关的。
为了支持一些编译时魔法,我想使用指向成员的指针,例如:
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*
因为 int
和 double
不是基于和派生 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
) .同样,这两种类型是无关的。