Получение типа члена

ПРИМЕЧАНИЕ. Первоначально этот вопрос задавался еще в 2012 году. До того, как спецификатор decltype был полностью реализован всеми основными компиляторами. Вы не должны смотреть на этот код, если у вас нет доступа только к C++03. Все основные компиляторы, совместимые с C++11, теперь поддерживают decltype.

Есть ли простой способ получить тип члена?
В 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);

}

Я на самом деле делаю это (т.е. немного ленивый):

#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;

Но вместо того, чтобы заставлять пользователя указывать тип члена, я хочу, чтобы компилятор сгенерировал его прагматически.

#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;

person Martin York    schedule 14.01.2012    source источник
comment
Я не думаю, что C++ позволяет вам даже говорить о Person::age, не имея экземпляра Person   -  person Seth Carnegie    schedule 15.01.2012
comment
@SethCarnegie: Если это правда (а я думаю, что это может быть так), это несколько раздражает. Как узнать размер Person::age?   -  person Oliver Charlesworth    schedule 15.01.2012
comment
как насчет создания чего-то вроде typedef int Person::age_t;?   -  person greatwolf    schedule 15.01.2012
comment
sizeof без экземпляра. Попробуйте: sizeof(reinterpret_cast<Person*>(0) -> age) Я неправильно понял вопрос, @SethCarnegie?   -  person Aaron McDaid    schedule 16.01.2012
comment
@AaronMcDaid Я тоже думал об этом сегодня, когда использовал offsetof. Однако предпочитайте ответ MSN, потому что способ offsetof имеет неопределенное поведение.   -  person Seth Carnegie    schedule 16.01.2012


Ответы (3)


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

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

Это способ С++ 11. Это требует, чтобы вы использовали &Person::age вместо Person::age, хотя вы можете легко настроить макрос, чтобы сделать амперсанд неявным.

person MSN    schedule 14.01.2012
comment
Вау, это работает... но я не понимаю. Как &Person::age превращается в тип age, но применяя &Person::age к M T:: *? Что вообще означает или представляет M T:: *? - person j00hi; 15.07.2019

В С++ 2003 это нельзя сделать напрямую, но вы можете делегировать функции шаблону, который выводит тип:

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

int main() {
    deduce_member_type(&Person::age);
}
person Dietmar Kühl    schedule 14.01.2012
comment
Здесь тот же вопрос, что и для принятого ответа: что за декларация T S::* member? Я не понимаю, как &Person::age применяется к T S::* member. - person j00hi; 15.07.2019
comment
@j00hi: это указатель на элемент (переменная). Тип состоит из типа, содержащего член, и типа члена. Обычно указатели на члены используются с операторами .* или ->*. - person Dietmar Kühl; 15.07.2019

Поскольку в ваших примерах вы используете boost, я бы использовал TYPEOF из boost.

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

он работает очень похоже на decltype C++11.

http://en.wikipedia.org/wiki/C%2B%2B11#Type_inference в вашем случае:

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

вы можете сравнить типы decltype или BOOST_TYPEOF, которые выдает вам с typeinfo

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

вам нужно сделать правильный вектор людей с длиной> 14, чтобы пример работал.

gcc имеет typeof или typeof, делающие то же самое.

В качестве примечания. В приведенном вами примере вы можете просто определить типы в структуре, если ни один из вышеперечисленных не имеет отношения к вам.

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

затем используйте std::vector‹ Person::agetype > ages;

person Johan Lundberg    schedule 14.01.2012