Le temps de compilation sizeof_array sans l'aide d'une macro
C'est juste quelque chose qui m'a gêné pour le couple des derniers jours, je ne pense pas que c'est possible de le résoudre mais j'ai vu un modèle de magie avant.
Va ici:
Pour obtenir le nombre d'éléments dans un standard C++ tableau que je pouvais utiliser une macro (1), ou un typesafe fonction inline (2):
(1)
#define sizeof_array(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
(2)
template <typename T>
size_t sizeof_array(const T& ARRAY){
return (sizeof(ARRAY)/sizeof(ARRAY[0]));
}
Comme vous pouvez le voir, le premier a le problème d'être une macro (pour le moment je considère qu'un problème) et l'autre a le problème de ne pas être en mesure d'obtenir la taille d'un tableau au moment de la compilation, c'est à dire je ne peux pas écrire:
enum ENUM{N=sizeof_array(ARRAY)};
ou
BOOST_STATIC_ASSERT(sizeof_array(ARRAY)==10);//Assuming the size 10..
Personne ne sait si cela peut être résolu?
Mise à jour:
Cette question a été créé avant constexpr a été introduit. Aujourd'hui, vous pouvez simplement utiliser:
template <typename T>
constexpr auto sizeof_array(const T& iarray) {
return (sizeof(iarray) / sizeof(iarray[0]));
}
OriginalL'auteur Viktor Sehr | 2009-09-30
Vous devez vous connecter pour publier un commentaire.
Essayez les opérations suivantes à partir ici:
Il devrait imprimer: "Le tableau de comptage est de: 10
+1. Cela a l'avantage d'être typesafe (c'est à dire, il ne pourra pas compiler si vous passez un pointeur au lieu d'un tableau).
Impressionnant solution.
Son une belle solution, mais pas complètement général: "il ne fonctionne pas avec des types définis à l'intérieur d'une fonction"
Les modèles en général ne fonctionne pas si bien pour les types définis à l'intérieur d'une fonction. En fait, il ne fonctionne pas pour STL -- le suivant ne compile pas sous GCC: void test() { struct foo{ int a; }; std::vector<foo> b; } Vous êtes beaucoup mieux d'utiliser un espace de noms (ou anonyme d'espace de noms) si vous avez besoin de créer une classe qui ne doit être utilisé que par une seule fonction et vous devez utiliser des modèles dans cette catégorie.
OriginalL'auteur Adisak
En C++1x
constexpr
obtiendrez vous que:Mais en C++98, il ne peut pas être utilisé lorsqu'une expression constante est prévu
Yep... ne fonctionnent pas sur un enum -- au moins sur un de mes pré-C++1X actuel compilateurs C++ que j'ai utiliser pour le travail.
OriginalL'auteur dalle
Le mieux je pense est de cette:
qui doit être utilisé avec un autre
sizeof
:[MODIFIER]
Venez pour penser à elle, je crois que c'est prouvable impossible de le faire en une seule fonction "-comme l'appellent" en C++03, en dehors de macros, et voici pourquoi.
D'une part, vous avez évidemment besoin de paramètre de modèle de la déduction pour obtenir la taille du tableau (soit directement, soit par
sizeof
comme vous le faites). Toutefois, le paramètre de modèle déduction est applicable uniquement à des fonctions, et non pas à des classes; c'est à dire que vous pouvez avoir un modèle de paramètre R de type de référence-de-tableau-de-N, où N est un autre paramètre du modèle, mais vous aurez à fournir à la fois R et N au moment de l'appel; si vous voulez en déduire N de R, mais seulement un appel de fonction ne peut le faire.D'autre part, la seule façon de toute expression impliquant un appel de fonction peut être constante, c'est quand il est à l'intérieur de
sizeof
. Rien d'autre (par exemple l'accès à un statique ou membre enum sur la valeur de retour de la fonction) nécessite encore l'appel à la fonction se produire, ce qui implique, bien sûr, ce ne sera pas une expression constante.const
de le rendre plus générique.Merci pour l'astuce. Il sera en mesure de déduire
T
commeconst U
si elle obtient unconst U[N]&
comme argument, non?J'aime utiliser l'identité dans ces cas, car il améliore grandement la lisibilité:
template<typename T, size_t N> typename identity<char[N]>::type &sizeof_array(T const(&)[N]);
. Pour leconst
retrait de ce fait diminué genericity. Parce que maintenant, vous ne pouvez pas accepter rvalue tableaux plus (non-const tableau de référence ne se lient pas à rvalue tableaux):struct A { int b[2]; }; .. sizeof_array(A().b); // doesn't work if it's not const!
. Notez que cette rvalue tableau n'est pas const lui-même, de sorte que la déduction ne mettra pas const. Notez que ce n'est pas un gros problème - mais sans doute, il est moins générique, je pense.La rvalue tableau n'est pas
const
lui-même, mais son type d'élément estconst
, alors pourquoi ne serait-il pas déduit? Comme une note côté, les deux MSVC et (plus rassurant) Comeau sont en mesure de déduireT
commeconst int
lors du passage deconst int a[10]
l'amende juste.Notez qu'il est très bien pour l'
T const(&)[N]
à accepter la non-const tableaux. Déduction s'en déduireT
normalement et de ne pas se laisser distraire par les autres const. Il favorise l'utilisation deconst
au lieu de cela ne serait pas bon si la déduction serait de forcer les gens à omettreconst
s'ils veulent accepter la non-const arguments. 🙂 De toute façon, upvoted vous à cause de votre belle analyse et sain d'esprit de nommage (pas fou souligne en face de noms etc xD).OriginalL'auteur Pavel Minaev
Le Problème
J'aime Adisak réponse:
C'est ce que Microsoft utilise pour la _countof macro dans VS2008, et il a quelques fonctionnalités intéressantes:
Mais comme l'a souligné Georg, cette approche utilise des modèles, il est donc pas de la garantie de travailler avec les types de C++03:
Heureusement, nous ne sommes pas hors de la chance.
La Solution
Ivan Johnson est venu avec une approche astucieuse qui gagne sur tous les comptes: c'est typesafe, au moment de la compilation, et travaille avec des locaux types:
Pour ceux qui sont intéressés, il fonctionne en insérant deux "tests" avant de la norme sizeof tableau de base-la taille de la macro. Ces tests ne sont pas d'incidence sur le calcul final, mais sont conçus pour générer des erreurs de compilation pour les non-type de matrice:
arr
est partie intégrante, enum, pointeur, ou d'un tableau.reinterpret_cast<const T*>
doit échouer pour tous les autres types.Le deuxième test échoue pour l'intégrale, enum, ou de type pointeur.
Intégral et les types enum va échouer, car il n'y a pas de version de
check_type
qu'ils correspondent, depuischeck_type
attend pointeurs.Types de pointeur échouent parce qu'ils correspondent à la templated version de
check_type
, mais le type de retour (Is_pointer
) pour l'basées sur des modèles decheck_type
est incomplète, ce qui produira une erreur.Types de tableau va passer parce que prendre l'adresse d'un tableau de type
T
vous donnera
T (*)[]
, aka un pointeur vers un tableau, pas un pointeur vers un pointeur. Cela signifie que le basé sur un modèle de la version decheck_type
ne correspond pas. Grâce à SFINAE, le compilateur va passer à la non-basé sur un modèle de la version decheck_type
, qui doit accepter n'importe quelle paire de pointeurs. Depuis le type de retour de la non-basé sur un modèle version est totalement défini, aucune erreur ne sera produite. Et comme nous ne sommes pas traiter avec des modèles de maintenant, des types locaux, beau travail.J'aime Ivan Johnson idée, mais je suis un peu confus. En C++11 il y a des solutions plus simples, donc, nous allons supposer que nous n'avons pas. Ensuite, les modèles ne capte pas les classes locales, afin de ne pas
localClass x; std::size_t length = COUNTOF(&x);
compiler? (Désolé, je n'ai pas de compilateur qui met en œuvre ce vieux "fonction" à portée de main.)Je suis peut-être trompé. L'appel de
COUNTOF(&x)
pourrait conduire à un essayer pour instancier leIs_pointer check_type
aveclocalClass
comme letemplate
paramètre, à cause peut-être une erreur de compilation (plutôt que de simplement SFINAE). Je ne peux pas dire si c'était déjà garanti par la norme ou juste pas clair et assumé.J'ai testé cela sur
g++
. En C++11 mode tout semblait fonctionner correctement, mais non C++11 modeg++
était "heureux" pour compilerLocalType x; LocalType *ptr = &x; std::size_t length = COUNTOF(ptr);
aveclength
arriver, bien sûr, une valeur complètement dénuée de sens. Si c'est une "extension", une interprétation valide de l'ambiguïté d'un standard, ou un bug est clair pour moi, mais peu importe, il semble qu'une toute type-safe version qui gère les types locaux est hors de portée avant C++11.OriginalL'auteur Nate Kohl
Ce n'est pas exactement ce que vous cherchez, mais il est proche - un extrait de
winnt.h
qui comprend une explication de ce que l' #$%^ c'est fait:La
RTL_NUMBER_OF_V2()
la fin de la macro est utilisé dans la plus lisibleARRAYSIZE()
macro.Matthew Wilson "Imparfaite C++" livre a aussi une discussion sur les techniques qui sont utilisées ici.
+1 : Lecture de la countOf code a me laisse perplexe (j'essaie de ne pas passer beaucoup de temps à maîtriser le côté obscur des règles de déclaration de C++ hérité de C). Cette réponse fournit exactement les infos sur ce qui est exactement RtlpNumberOf.
OriginalL'auteur Michael Burr
Si vous êtes sur une seule plate-forme Microsoft, vous pouvez profiter de la _countof macro. C'est un non-standard de l'extension qui va retourner le nombre d'éléments dans un tableau. C'est un avantage sur la plupart des countof style des macros, c'est qu'il va provoquer une erreur de compilation si elle est utilisée sur un non-type de tableau.
Le suivant fonctionne très bien (VS 2008 RTM)
Mais encore une fois, c'est MS, de sorte que cela peut ne pas fonctionner pour vous.
OriginalL'auteur JaredPar
Vous ne pouvez pas le résoudre en général, c'est l'une des raisons pour tableau wrappers comme boost tableau (plus de stl, style de comportement, bien sûr).
Développez sur votre façon de résoudre les deux exemples précis dans la question sans macros pré-C++11. La question était à l'origine sur la façon de les résoudre sans faire des macros.
Observer Nate Kohls réponse par exemple stackoverflow.com/a/6256085/239916. (Il utilise une macro, mais c'est juste une commodité; il n'est pas nécessaire.) Je n'ai pas essayé, mais je crois qu'il devrait être possible et assez simple à émuler
decltype
en C++03, donc, on peut écrire l'équivalent de C++11 eststd::extent<std::enable_if<std::is_array<decltype(x)>::value, decltype(x)>::type>::value
en C++03. Oui, ces traits de caractère n'existe pas en natif en C++03, mais ceux-ci sont certainement applicables.Cette réponse est intéressante si elle fonctionne correctement avec des types locaux, mais sans les macros c'est effectivement inutilisable (comme dans, vous ne pourrez pas l'utiliser dans la pratique). L'émulation
decltype
en C++03 n'est pas possible. Aussi, la réduction des expressions comme ci-dessus en C++03 à longueur utile/syntaxe des sons réalistes.Vous avez raison. J'ai pensé que certaines choses ont été possible de le faire en C++ (même en C++11) qui ne sont pas possible de le faire quand j'ai essayé d'écrire un peu de code pour cela. Je ne peux pas retirer mon downvote apparemment... wow.
OriginalL'auteur Georg Fritzsche
Il ne semble pas possible d'obtenir le sizeof tableau comme une constante de compilation sans une macro avec l'actuelle norme C++ (vous avez besoin d'une fonction pour en déduire la taille de la matrice, mais les appels de fonction ne sont pas autorisés lorsque vous avez besoin d'une constante de compilation). [Edit: Mais voir Minaev brillante solution!]
Cependant, votre version du modèle n'est pas typesafe et souffre du même problème que la macro: il accepte aussi les pointeurs et notamment des tableaux pourri à un pointeur. Lorsqu'il accepte un pointeur, le résultat de sizeof(T*) /sizeof(T) ne peut pas être significative.
Mieux:
OriginalL'auteur UncleBens
Sans C++0x, le plus proche que je puisse obtenir est:
qui vous donne une fonction, vous pouvez transmettre la variable, ou d'un modèle, vous pouvez passer le type de trop. Vous ne pouvez pas utiliser la fonction pour une compilation constante de temps, mais la plupart des cas vous connaissez le type, même si seulement en tant que paramètre du modèle.
constexpr
- comme d'autres réponses ont souligné.Après avoir lu ce post, j'ai mis "Sans C++0x" au début de la mine de montrer que je n'étais pas à l'aide de cette technique, mais qui va travailler avec les compilateurs gcc.
La constante de compilation version a l'air un peu inutile, mais. Pourquoi voudriez-vous avoir à passer par la peine de taper count_of_type<int[20]>::valeur si vous devez connaître la taille est de 20? 🙂
Vous pourriez count_of_type<T>::valeur où T est un paramètre du modèle, mais je suis d'accord qu'il est susceptible d'être rares.
OriginalL'auteur Pete Kirkham
Maintenant STL bibliothèques sont disponibles pour décider/sélectionner la taille de la matrice moment de la compilation
De sortie:
3
OriginalL'auteur Hariom Singh