1

Searching the site I found this answer for getting a type of a member inside a class. Based on that I made the following example which compiles succesfully.

#include <iostream>
#include <stdio.h>
#include <string>

using namespace std;


class sig_class_t{
public:
    int field;
};

class usig_class_t{
public:
    unsigned int field;
};

template <class T, class M> M get_member_type(M T:: *);

template<typename my_class = sig_class_t, typename my_type = decltype(get_member_type(&my_class::field))>
class Tricky{
    my_type it;
public:
    my_type get_it();
    void set_it(my_type value);
};

template<typename my_class, typename my_type>
my_type Tricky<my_class,my_type>::get_it(){
    return it;
}

template<typename my_class, typename my_type>
void Tricky<my_class,my_type>::set_it(my_type value){
    it = value;
}

int main(int argc, char *argv[])
{
    return 0;
}

How does get_member_type is able to decide the type of the given pointer?
This code seems a quite complex, and I would not be comfortable using it if I don't understand how it works.

Dávid Tóth
  • 2,788
  • 1
  • 21
  • 46

2 Answers2

2

With

template<typename my_class = sig_class_t, 
         typename my_type = decltype(get_member_type(&my_class::field))>
class Tricky{
    my_type it;
public:
    my_type get_it();
    void set_it(my_type value);
};

You pass &my_class::field to get_member_type. &my_class::field is a pointer to the field member of myclass so it has type

decltype(my_class::field) myclass::*

or to put in it english, a myclass member pointer to the type of the field member. By default (since it uses sig_class_t) that is

int sig_class_t::*

Why you pass that to

template <class T, class M> M get_member_type(M T:: *);

M gets deduced as int and T gets deduced to sig_class_t. The function then "returns" an object of type M, so decltype(get_member_type(&my_class::field)) resolves to M (int in the default case) and that is how my_type gets deduced to being the type that the pointer points to.

Dávid Tóth
  • 2,788
  • 1
  • 21
  • 46
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • phew.. it's not easy to wrap your head around it.. Almost got it, but how does the `get_member_type` token just disappear? – Dávid Tóth Mar 24 '20 at 14:36
  • 1
    @DavidTóth because of `decltype`. `get_member_type` is what is called a meta function. That is a function that takes a thing(s) and return something, and you use that return type in a template context. In this case `decltype` doesn't actually call the function but looks at what type it would return if it had, and returns that type. – NathanOliver Mar 24 '20 at 14:40
  • Okay, this clicked! Thank you! – Dávid Tóth Mar 24 '20 at 14:42
1

While this is not a direct answer to your question, I find this expression easier to understand:

decltype(std::declval<my_class>().field)

The std::declval<my_class>() part returns a "dummy" my_class object, so we can use .field on it. And this subexpression is wrapped in decltype, which will give field's type.

(Note, that declval can only be used in an unevaluated context. decltype's parameter is such a context.)

geza
  • 28,403
  • 6
  • 61
  • 135