2017-08-22 6 views
3

Existe-t-il un moyen d'obtenir le nombre de champs d'une classe?obtenir le nombre de champs dans une classe

struct Base { 
    char a; 
    int b; 
}; 

struct Derived : Base { 
    std::string c; 
}; 

static_assert(num_fields<Base>::value == 2); 
static_assert(num_fields<Derived>::value == 1); 

J'ai trouvé this question mais il est très daté - J'espère que quelque chose peut être cousu avec 14/17 C++ (après tout ce que nous avons maintenant quelque chose comme magic_get - peut-être un sous-ensemble de celui-ci .. .?)

EDIT: - un crochet du compilateur fonctionnerait également, même si elle est seulement pour MSVC ou GCC ou Clang - Je l'utilise tous les 3.

+5

Quel est le cas d'utilisation pour cela? Peut-être qu'une solution différente pourrait être trouvée là –

+1

Rien de ce que je sais de cela n'implique de macro kung-fu. Je suggère d'utiliser 'std :: tuple' quand vous avez besoin d'itérer ou de compter les champs. – AMA

+0

C++ ne fonctionne pas comme ça. Fait intéressant, beaucoup de ces questions ont surgi récemment. – kim366

Répondre

3

En effet, Antony Polukhin nous a montré que C++ a avoir une réflexion, depuis C++ 14, sans le savoir; et que vous pouvez extraire des informations sur les champs. ... bien, au moins pour les structures/classes de données anciennes. Regardez ses CppCon 2016 talk:

C++14 Reflections Without Macros, Markup nor External Tooling/Antony Polukhin

Et puis vous écrivez:

template <class T, std::size_t I0, std::size_t... I> 
constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>) 
    -> decltype(T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... }) 
{ out = sizeof...(I) + 1;  /*...*/ } 

template <class T, std::size_t... I> 
constexpr void detect_fields_count(std::size_t& out, std::index_sequence<I...>) { 
    detect_fields_count<T>(out, std::make_index_sequence<sizeof...(I) - 1>{}); 
} 

qui vous obtient le nombre de champs. Bien sûr, vous avez également besoin de la structure ubiq intelligemment conçue. Qu'est-ce que vous avez réellement besoin d'utiliser est ces deux fichiers:

https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/config.hpp
https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/fields_count.hpp

et cela devrait être suffisant.

+0

Pensez-vous qu'il est également possible de le faire fonctionner avec des champs privés? Cela fait un type ** non agrégable initialisable ** mais peut-être en amalgamant certaines des fonctions constexpr ou les classes de traits de structure ...? – onqtam

+0

@onqtam: J'en doute, mais - je ne suis pas un fou de génie russe, alors qui sait ... – einpoklum

+1

Cela ne fonctionnera pas non plus pour 'Derived'; ce n'est pas un agrégat car il a une classe de base et donc [ne peut pas être initialisé globalement] (https://stackoverflow.com/questions/23808357/brace-initialization-for-inherited-pod). – rustyx

7

Vous ne pouvez pas le faire (hors de la boîte) car il n'y a pas de réflexion en C++ (pour le moment). Vous devez explorer d'autres options telles que les bibliothèques tierces.

+0

* "Vous ne pouvez pas faire ça), car il n'y a pas de réflexion en C++. "* - J'espère que cette déclaration se termine par un **" encore "**, parce qu'il y a des efforts continus pour en apporter une forme ... Peut-être verrons-nous C++ 20 ?? C++ 23 ??? – WhiZTiM

+2

Vous pouvez * le faire avec TMP. Jetez un coup d'œil à [magic_get] (https://github.com/apolukhin/magic_get) et [binding structuré] (http://en.cppreference.com/w/cpp/language/structured_binding). – rustyx

+1

Ron: O RLY? En fait, vous pouvez certainement le faire hors de la boîte. Et C++ a une réflexion (elle ne le sait pas encore ...); vois ma réponse. – einpoklum