18

NOTE: This question was originally asked way back in 2012. Before the decltype specifier was fully implemented by any major compilers. You should not be looking at this code unless you only have access to C++03. All major C++11 compliant compilers now support decltype.

Is there an easy way to retrieve the type of a member?
In C++03

struct Person
{
    std::string name;
    int         age;
    double      salary;
};

int main()
{
    std::vector<Person>     people; //  get a vector of people.

    std::vector<GET_TYPE_OF(Person::age)>   ages;

    ages.push_back(people[0].age);
    ages.push_back(people[10].age);
    ages.push_back(people[13].age);

}

I am actually doing this (ie being slightly lazy):

#define BuildType(className, member, type)                                 \
        struct className ## member: TypeBase<className, type>              \
        {                                                                  \
            className ## member()                                          \
                : TypeBase<className, type>(#member, &className::member)   \
            {}                                                             \
        }

BuildType(Person, name,     std::string);
BuildType(Person, age,      int);
BuildType(Person, salary,   double);
typedef boost::mpl::vector<Personname, Personage, Personsalary> FunckyMTPMap;

But rather than have to force the user to specify the type of the member I want to the compiler to generate it pragmatically.

#define BuildType(className, member)                                                  \
struct className ## member: TypeBase<className, TYPE_OF(className ## member)>         \
{                                                                                     \
   className ## member()                                                              \
      : TypeBase<className, TYPE_OF(className ## member)>(#member, &className::member)\
   {}                                                                                 \
}
BuildType(Person, name);
BuildType(Person, age);
BuildType(Person, salary);
typedef boost::mpl::vector<Personname, Personage, Personsalary> FunckyMTPMap;
Martin York
  • 257,169
  • 86
  • 333
  • 562

3 Answers3

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

#define GET_TYPE_OF(mem) decltype(get_member_type(mem))

Is the C++11 way. It requires you to use &Person::age instead of Person::age, although you could easily adjust the macro to make the ampersand implicit.

MSN
  • 53,214
  • 7
  • 75
  • 105
  • 5
    Wow, it works... but I don't get it. How is `&Person::age` turned into the type of `age`, but applying `&Person::age` onto `M T:: *`? What does `M T:: *` even mean or represent? – j00hi Jul 15 '19 at 13:32
  • See also [C++ typename of member variable](https://stackoverflow.com/a/2474401/94687), which suggests for C++11 the use of `decltype` as simple as `decltype(Person::age)`. – imz -- Ivan Zakharyaschev Oct 08 '21 at 13:38
6

In C++2003 it can't be done directly but you can delegate to a function template which deduces the type:

template <typename T, typename S>
void deduce_member_type(T S::* member) {
     ...
}

int main() {
    deduce_member_type(&Person::age);
}
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Same question here, as for the accepted answer: What kind of declaration is `T S::* member`? I don't get it, how `&Person::age` gets applied to `T S::* member`. – j00hi Jul 15 '19 at 13:36
  • 1
    @j00hi: it is a _pointer-to-member_ (variable). The type is composed of the type containing the member and the member type. The normal use of pointer-to-members is with the `.*` or `->*` operators. – Dietmar Kühl Jul 15 '19 at 13:42
1

Since in your examples you use boost I'd use TYPEOF from boost.

http://www.boost.org/doc/libs/1_35_0/doc/html/typeof.html

it works very similarly to decltype of C++11.

http://en.wikipedia.org/wiki/C%2B%2B11#Type_inference in your case:

std::vector<BOOST_TYPEOF(Person::age) > ages;

you can compare the types decltype or BOOST_TYPEOF gives you with typeinfo

#include <typeinfo>
cout << typeid(obj).name() << endl;

you need to make a proper people vector with length >14 for the example to work.

gcc has typeof or typeof doing the same thing.

As a side note. For the example you gave you could just define the types in the struct instead if none of the above is relevant for you.

struct Person
{
  typedef  int agetype;
  std::string name;
  agetype         age;
  int         salary;
};

then use std::vector< Person::agetype > ages;

Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97