0

I think this question is related to C++ pointer to member of derived class, but slightly different.

I have a class accepts a pointer-to-member as template parameter, and will deduct the holder's type from pointer-to-member, with the helper described in Inferring type and class when passing a pointer to data member as a non-type template argument.

If the holder is a derived class and the member is from the base class, the deducted type of holder is Base. Even if I pass the pointer-to-member in form Derived::*. The code below is the minimal reproducible example, also available at https://godbolt.org/z/9rEc1876E

I'm using gcc with -std=c++20.

My question is:

  1. In TypeFromMember helper, both T = Base and T = Derived should match the template specification. How and why the compiler decides to match T = Base?

  2. How can I modify the implementation of TypeFromMember so that it can correctly deduct Derived instead of Base when I actually pass &Derived::node as ptr-to-member?

Note: I can modify the LinkedList's template parameters to template<auto PtrToMember, class T = typename TypeFromMember<decltype(PtrToMember)>::ClassType>, and pass correct T manually in such case. I just wonder if the helper can do this automatically.

#include <type_traits>

struct Node{};

class Base
{
public:
    Node node;
};

class Derived : public Base {};

// https://stackoverflow.com/questions/65375734/inferring-type-and-class-when-passing-a-pointer-to-data-PtrToMember-as-a-non-type-tem
template <typename T> struct TypeFromMember;
template <typename T,typename M>
struct TypeFromMember<M T::*>
{
    using ClassType = T;
    using MemberType = M;
};


template<auto PtrToMember>
class LinkedList
{
    using T = typename TypeFromMember<decltype(PtrToMember)>::ClassType;
public:
    T *front()
    {
        return new T(); // just for verify the type
    }
};

int main()
{
    LinkedList<&Base::node> bl;
    LinkedList<&Derived::node> dl;
    static_assert(std::is_same_v<decltype(bl.front()), Base*>); // Pass
    static_assert(std::is_same_v<decltype(dl.front()), Base*>); // Pass
    // static_assert(std::is_same_v<decltype(dl.front()), Derived*>); // Fail, decltype(dl.front()) is Base*
}
3
  • 2
    The type of &Derived::node is Node Base::*, since node is a member of Base. The standard even has an example exactly like this: struct A { int i; }; struct B : A { }; ... &B::i ... // has type int A::* So there's no way to deduce Derived, as Derived is not part of the type to begin with. Commented Dec 31, 2024 at 5:53
  • @IgorTandetnik I see. Thank you for replying. So there is no type named Node Derived::* here, it's just an alias for Node Base::*? Commented Dec 31, 2024 at 6:34
  • 1
    Node Derived::* is not an alias for anything. It's a separate type. The point is that the type of &Derived::node is not Node Derived::* even though it looks like it should be. It's the same as asking what happened to the float when you write 0. Nothing "happened to" the float. The float was never there. Commented Dec 31, 2024 at 7:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.