I thought it is straightforward that a 'pointer to member of class T of type DerivedT' can be used as a 'pointer to member of class T of type BaseT' if BaseT is base of DerivedT. The analogy seems to be obvious at least to me as DerivedT* can be used as a BaseT*, so DerivedT T::* should be able to be used as BaseT T::*
But it is not the case:
struct BaseT
{
};
struct DerivedT: public BaseT
{
};
struct T
{
DerivedT m_test;
};
using BaseTMemPtr = BaseT T::*;
int main()
{
T test;
BaseT* simplePtr = &test.m_test; //It is DerivedT*, but can be used as BaseT*
BaseT (T::*memPtr) = &T::m_test; //Error, BaseT T::* cannot be used as DerivedT T::*
BaseTMemPtr memPtr2 = &T::m_test; //Error, just the same
}
As I see there are two ways to interpret pointers to class members:
- DerivedT T::* is a DerivedT pointer that points to a DerivedT object inside an object of T class (so points an object relative to another object)
- DerivedT T::* points to some part of an object of class T which has by the way DerivedT type.
So the main difference between this two ways is while the first one can be interpreted as a kind of DerivedT pointer (enabling polymorphism), the later one kind of discards the type and restrict the usage a lot.
Why did C++ choose the second approach? What could be the unwanted consequence of enabling using DerivedT T::* as a BaseT T::* ? What are pointers to members in practice?
UPDATE: I would like to achieve the following: Desired solution But it does not work if the members are not BaseMember types but BaseMember descendants. The concept works if I use BaseMembers (but in this case I cannot implement the desired member functionality): Works with broken functionality
UPDATE 2: Why
TLDR:
A way to compile time 'mark' (uniquely identify) a non-static member object of a runtime constructed class. Then check if a regular (non-member) pointer was compile-time marked or not in a runtime function that has
1, the compile time array of the marked members (can be anything, in my mind the polymorphic pointers-to-members)
2. 'this' pointer of the containing object (that has the marked and unmarked members)
3, the regular (non-pointer-to-member) pointer to the non-static member object.
Timeline: class definition (compile time) -> add class members (compile time) -> mark class members as enabled - e.g. in an array - (compile time) -> construction (runtime) -> members will call register function (runtime) -> in register function we need to check if the caller (we receive it as a regular pointer) is allowed to call this function or not (runtime).
Long description:
In a library I have a CRTP base class (DataBinding) that the users should descend from if they would like to use its compile- and runtime functionality.
Then in the library I also have an interface class: BaseMember, and many derived classes of it. The end user can use the derived classes to add non-static class member objects in their user-defined DataBinding-descendant classes.
In the user code, in DataBinding-descendant user classes the user can have BaseMember based non-static class members. And here comes the new functionality that requires pointer-to-member polymorphism: The user should be able to mark some of BaseMember-based class members in compile time(!) (the class itself does not have constexpr constructor) - in my mind this 'mark' could be storing the pointer-to-member of the BaseMember descendant member object -, and only the marked objects should be allowed to runtime-call a class member function (registerMember) in DataBinding (CRTP base of the current class).
In the registerMember runtime function I have the "this" object pointer (the containing object), I have the compile time user defined list that marks the enabled pointers-to-members (it can be replaced with any kind of unique identification) and I have the actual member pointer. I need to check if the actual member pointer is allowed to call the function (it was marked compile time).