J'ai une fonction qui prend une dimension multidimensionnelle std::vector
et nécessite que la profondeur (ou le nombre de dimensions) soit transmise en tant que paramètre de modèle. Au lieu de coder en dur cette valeur, je voudrais écrire une constexpr
fonction qui prendra std::vector
et retournera la profondeur comme unsigned integer
valeur.
Par exemple:
std::vector<std::vector<std::vector<int>>> v =
{
{ { 0, 1}, { 2, 3 } },
{ { 4, 5}, { 6, 7 } },
};
// Returns 3
size_t depth = GetDepth(v);
Cela doit être fait au moment de la compilation, car cette profondeur sera transmise à la fonction de modèle en tant que paramètre de modèle:
// Same as calling foo<3>(v);
foo<GetDepth(v)>(v);
Y a-t-il un moyen de faire ça?
std::vector
est une chose au moment de l'exécution, pas à la compilation. Si vous voulez un conteneur de taille au moment de la compilation, recherchezstd::array
. Aussi; rappelez-vous que celaconstexpr
signifie seulement " peut être évalué au moment de la compilation" - il n'y a aucune promesse que ce sera le cas. Il peut être évalué au moment de l'exécution.std::vector
s sont imbriqués les uns dans les autres. Par exemple avecstd::vector<std::vector<int>> v;
,GetDepth(v);
renverrait 2 car il s'agit d'un vecteur bidimensionnel. La taille n'a pas d'importance.vector
n'est pas toujours la meilleure façon de faire les choses. L'indexation manuelle 2D ou 3D d'un seul vecteur plat peut être plus efficace, selon le cas d'utilisation. (Juste des mathématiques entières au lieu de chasser des pointeurs des niveaux extérieurs.)rank
pour cette requête sur les types de tableaux (en accord avec la nomenclature mathématique des tenseurs). Peut-être que c'est un meilleur mot ici que «profondeur».Réponses:
Un problème de modèle classique. Voici une solution simple comme la bibliothèque standard C ++. L'idée de base est d'avoir un modèle récursif qui comptera une par une chaque dimension, avec un cas de base de 0 pour tout type qui n'est pas un vecteur.
Vous pouvez donc l'utiliser comme ceci:
Éditer:
Ok, j'ai terminé l'implémentation générale pour tout type de conteneur. Notez que j'ai défini un type de conteneur comme tout ce qui a un type d'itérateur bien formé selon l'expression
begin(t)
oùstd::begin
est importé pour la recherche ADL ett
est une valeur de typeT
.Voici mon code avec des commentaires pour expliquer pourquoi les choses fonctionnent et les cas de test que j'ai utilisés. Notez que cela nécessite C ++ 17 pour être compilé.
la source
std::vector<T>
spécialisation et la changer en un autre type de conteneur. La seule chose dont vous avez besoin est le cas de base 0 pour tout type pour lequel vous n'êtes pas spécialiséSi l'on suppose qu'un conteneur est un type qui a
value_type
etiterator
types de membres (conteneurs bibliothèque standard satisfont à cette exigence) ou un tableau de style C, on peut facilement généraliser Cruz Jean solution de:Les types de conteneurs peuvent être davantage restreints si nécessaire.
la source
Vous pouvez définir le modèle de classe suivant
vector_depth<>
qui correspond à n'importe quel type:Ce modèle principal correspond au cas de base qui termine la récursivité. Définissez ensuite sa spécialisation correspondante pour
std::vector<T>
:Cette spécialisation correspond à un
std::vector<T>
et correspond au cas récursif.Enfin, définissez le modèle de fonction
GetDepth()
, qui utilise le modèle de classe ci-dessus:Exemple:
Le résultat de ce programme est:
la source
std::vector
, mais par exempleGetDepth(v)
oùv
estint
ne sera pas compilé. Ce serait mieux d'avoirGetDepth(const volatile T&)
et de revenirvector_depth<T>::value
.volatile
laisse juste couvrir plus de choses, étant qualifié de cv maximum