Как узнать количество полей в структуре?

123
29 мая 2019, 04:20

Как узнать количество полей в структуре?

struct A {
  int a,b; // 2 поля
}
struct B {
  float a,b,c; // 3 поля
}
Answer 1

В общем случае это невозможно.

В C++23 должны добавить рефлексию, с помощью которой это можно будет делать, но до тех пор придется довольствоваться разными сомнительными хаками.

Есть несколько решений для частных случаев:

Если у вас все поля в структуре одного типа, и вы знаете, какого именно, то, как предложил @ARHovsepyan, можно поделить размер структуры на размер одного ее члена:

int main()
{
    std::cout << sizeof(A) / sizeof(int) << '\n';
    std::cout << sizeof(B) / sizeof(float) << '\n';
}

Хотя, ЕМНИП, компиляторам разрешается добавлять в структуры сколько угодно неиспользуемых байт (padding) между и после полей, чтобы расположить их в памяти определенным образом (из-за чего этот трюк перестал бы работать), я еще не видел ни одного компилятора, который действительно делал бы это для структур с полями одного типа.

Есть еще один вариант, более универсальный.

Если вы не создали для вашей структуры ни одного конструктора, и в структуре нет полей-массивов, то можно сделать вот что:

#include <cstddef>
#include <iostream>
#include <experimental/type_traits>
#include <utility>
struct stub
{
    template <typename T> operator T() const;
};
template <typename T, typename ...P>
using detect_brace_constructible = decltype(T{std::declval<P>()...});
template <typename T, std::size_t ...I>
constexpr bool constructible_with_stubs(std::index_sequence<I...>)
{
    return std::experimental::is_detected_v<
        detect_brace_constructible, T, std::enable_if_t<1 || I, stub>...
    >;
}
template <typename T, std::size_t ...I>
constexpr int field_count_impl(std::index_sequence<I...>)
{
    int ret = -1;
    ((void(ret = I), constructible_with_stubs<T>(std::make_index_sequence<I>{})) && ...);
    return ret-1;
}
template <typename T, std::size_t MaxFieldCount = 32>
inline constexpr int field_count =
    field_count_impl<T>(std::make_index_sequence<MaxFieldCount+1>{});

struct A
{
    int a,b;
};
struct B
{
    float a,b,c;
};
int main()
{
    std::cout << field_count<A> << '\n'; // 2
    std::cout << field_count<B> << '\n'; // 3
}

Этот шаблон последовательно пробует конструировать структуру с возрастающим количеством аргументов:

A{}
A{stub{}}
A{stub{}, stub{}}
A{stub{}, stub{}, stub{}}
...

Где stub{} - это заглушка, которая может быть преобразована в любой нужный тип.

Такое конструирование будет успешно, пока заглушек столько же, сколько полей в структуре, или меньше. Если заглушек будет больше - будет ошибка. Мы эту ошибку обнаруживаем с помощью SFINAE и возвращаем число заглушек, при котором ошибки не было.

Но если в структуре есть массив, то такой шаблон ошибочно посчитает каждый элемент массива за отдельное поле структуры.

Answer 2

В добавление к существующему ответу: есть библиотека Precise and Flat Reflection, в которой реализован требуемый функционал. Там же можно посмотреть как всё сделано, если интересна реализация.

READ ALSO
Не могу собрать akelpad

Не могу собрать akelpad

Покажите как откомпилировать akelpad

145
VS2010, с++. Подсветка синтаксиса

VS2010, с++. Подсветка синтаксиса

1) Как сделать расширенную цветную подсветку синтаксиса кода в VS2010 для C++? Может, расширение какое-нибудьНапример, как в ReSharper C++ (имена методов...

123