Search code examples
c++typesmember-pointers

get type of member memberpointer points to


I would like to extract the type of the member a member pointer points to.

template<someType myClass::*member>
void demo(myClass& instance, void* ptr) {
    instance.*member = *reinterpret_cast<someType*>(ptr);  // can the someType in this line be deduced from member?
}

I tried using decltype as suggested in the comments, however I have issues with this:

instance.*member= static_cast<decltype(instance.*member)>((*buffer)[offset]);

buffer is a std::shared_ptr<std::vector<uint8_t>>,
someType is uint32_t

I get the following error message:

error: invalid static_cast from type ‘__gnu_cxx::__alloc_traits >::value_type {aka unsigned char}’ to type ‘uint32_t& {aka unsigned int&}’

As far as I understand decltype(instance.*member) with member defined as uint32_t instance::*member yields a reference uint32_t& rather than uint32_t. I tried to pass instance by value and the error remains. I am aware of std::remove_reference however, I do not understand how the reference gets to be there in the first place.

A further improvement would be if I could extract the someType without a class instance. However I have no clue how to achieve this, while I can get the class without a pointer by having the std lib like:

template <T*>
struct removePointer {
  typedef T type;
}

I have no Idea how to write this in a form where I can get the someType part of the class, without knowing the class first. I could write something like the following however I would still have to pass the class naem and typename explicitly, is there a way to extract these automatically? Furthermore the following doe not compile in the first place (http://ideone.com/8VlKO4): #include using namespace std;

template <class C,typename T, T C::*v>
struct getPointerType {
typedef T type;
};

class Test {
int value;
};

int main() {
int Test::*member=nullptr;
cout << typeid(getPointerType<Test, int, decltype(member)>::type) << std::endl;
return 0;
}

Solution

  • Frankly, it's a bit hard to understand what you're trying to achieve, so I will focus on the updated part.

    Clearly, you can not pass types (derived from decltype) as value arguments to the template. Moreover, you can not pass non constexpr values as template arguments (so you can not just stick the member variable into the template argument and expect it to compile).

    However, you can rely on compiler to be able to deduce a correct function to call on non costexpr variable:

    template <class C, typename T>
    T getPointerType(T C::*v);
    
    class Test {
        int value;
    };
    
    int main() {
        int Test::*member=nullptr;
        cout << typeid(decltype(member)).name() << std::endl;
        cout << typeid(decltype(getPointerType(member))).name() << std::endl;
        return 0;
    }
    

    The above will print:

    M4Testi //int Test::*
    i       //int
    

    It is, of course, possible to "abuse" the template substitution even more:

    template <typename M>
    struct getPointerType {
       template <typename C, typename T>
       static T get_type(T C::*v);
    
       typedef decltype(get_type(static_cast<M>(nullptr))) type;
    };
    
    class Test {
        int value;
    };
    
    int main() {
        int Test::*member=nullptr;
        cout << typeid(getPointerType<decltype(member)>::type).name() << std::endl;
        return 0;
    }
    

    The output will be the expected "i".