Le passage d'un std::array de taille inconnue à une fonction
En C++11, comment pourrais-je aller sur l'écriture d'une fonction (ou méthode) qui prend un std::array de type connu, mais inconnue de taille?
//made up example
void mulArray(std::array<int, ?>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
//lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
Au cours de ma recherche je n'ai trouvé que des suggestions pour l'utilisation des modèles, mais ceux qui semble désordonné (définitions de méthode dans l'en-tête) et excessif pour ce que je suis en train d'accomplir.
Est-il un moyen simple pour faire ce travail, comme on le ferait avec du C-style des tableaux?
- Les tableaux ont pas de limites de la vérification ou de savoir de quelle taille ils sont. Par conséquent, vous devez mettre dans quelque chose, ou d'envisager l'utilisation de
std::vector
. - Si des modèles semble désordonnée et excessive, vous devez obtenir plus de ce sentiment. Ils sont monnaie courante en C++.
- Aucune raison de ne pas utiliser
std::vector
comme @TravisPessetto recommande? - Compris. Si ce une limitation de leur nature, je vais devoir l'accepter. La raison que j'ai pensé en évitant les std::vector (qui fonctionne très bien pour moi), c'est qu'il est alloué sur le tas. Depuis ces tableaux sera minuscule et boucle à travers à chaque itération du programme, j'ai pensé qu'un std::array pourrait effectuer un peu mieux. Je pense que je vais utiliser un style C tableau puis, mon programme n'est pas complexe.
- Votre façon de penser à propos de la performance est tout à fait faux. N'essayez pas d'effectuer des micro-optimisations avant même d'avoir un programme fonctionnel. Et après vous avez un programme, n'essayez pas de deviner sur ce que doit être optimisée, au lieu de laisser un profileur de vous dire dans quelle partie du programme doit être optimisé.
Vous devez vous connecter pour publier un commentaire.
Pas. Vous vraiment ne peut pas le faire sauf si vous faire de votre fonction une fonction modèle (ou utiliser un autre type de conteneur, comme une
std::vector
, comme suggéré dans les commentaires à la question):Ici est un live exemple.
template<typename C, typename M> void mulArray(C & arr, M multiplier) { /* same body */ }
tcc
fichier de modèle de définitions de méthode, et je#include
de la 'h' de fichiers de définitions distinctes de déclarations, mais il reste compile bien.La taille de la
array
est partie du type d', de sorte que vous ne pouvez pas faire tout ce que vous voulez. Il ya un couple de solutions de rechange.Préféré serait de prendre une paire d'itérateurs:
Alternativement, utilisez
vector
au lieu de la matrice, ce qui vous permet de stocker la taille au moment de l'exécution plutôt que dans le cadre de son type:J'ai essayé ci-dessous et il a travaillé pour moi.
De SORTIE :
1 2 3 4 5 6 7
2 4 6 8 10 12
1 1 1 1 1 1 1 1 1
3 6 9 12 15 18 21
10 20 30 40 50 60
2 2 2 2 2 2 2 2 2
template
.auto foo(auto bar) { return bar * 2; }
n'est pas valide en C++, même si il compile en GCC7 avec le C++17 indicateur. À la lecture de ici, les paramètres de la fonction déclarée comme auto font partie des Concepts TS qui devrait finalement être de la partie C++20.Absolument, il existe une méthode simple en C++11 pour écrire une fonction qui prend un std::array de type connu, mais inconnue de taille.
Si nous sommes incapables de passer la taille du tableau à la fonction, au lieu de cela, nous pouvons passer l'adresse de la mémoire de l'endroit où le tableau commence avec une 2ème adresse de l'endroit où le tableau se termine. Plus tard, à l'intérieur de la fonction, nous pouvons utiliser ces 2 adresses de mémoire pour calculer la taille du tableau!
À la sortie de la Console: 10, 20, 2, 4, 8
MODIFIER
C++20 provisoirement comprend
std::span
https://en.cppreference.com/w/cpp/container/span
Réponse Originale À Cette Question
Ce que vous voulez, c'est quelque chose comme
gsl::span
, qui est disponible dans la note d'Orientation Bibliothèque de prise en charge décrite dans le C++ lignes Directrices de Base:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views
Vous pouvez trouver un open-source d'en-tête uniquement de la mise en œuvre de la GSL ici:
https://github.com/Microsoft/GSL
Avec
gsl::span
, vous pouvez le faire:Le problème avec
std::array
est que sa taille est partie de son type, de sorte que vous auriez à utiliser un modèle afin de mettre en œuvre une fonction qui prend unstd::array
de taille arbitraire.gsl::span
d'autre part les magasins de sa taille au moment de l'exécution des informations. Cela vous permet d'utiliser un non-fonction de modèle à accepter un tableau de taille arbitraire. Il accepte également d'autres contiguë conteneurs:Assez cool, hein?
Cela peut être fait, mais il ne prend que quelques étapes à faire proprement. Tout d'abord, écrire un
template class
qui représente une plage contiguë de valeurs. Puis le transférer à untemplate
version qui sait comment taille lesarray
est à laImpl
version qui prend cette plage contiguë.Enfin, de mettre en œuvre la
contig_range
version. Notez quefor( int& x: range )
fonctionne pourcontig_range
, parce que j'ai mis en placebegin()
etend()
et les pointeurs sont des itérateurs.(pas testé, mais le design devrait fonctionner).
Puis, dans votre
.cpp
fichier:Cela a l'inconvénient que le code qui effectue une boucle sur le contenu de la matrice ne sait pas (au moment de la compilation) la taille du tableau, ce qui pourrait l'optimisation des coûts. Il a l'avantage de la mise en œuvre n'a pas à être dans l'en-tête.
Être prudent au sujet de construire explicitement un
contig_range
, comme si vous passer unset
il suppose que leset
données est contiguë, ce qui est faux, et ne pas défini le comportement de tous sur la place. Les deux seulsstd
conteneurs que cela est garanti pour fonctionner sur sontvector
etarray
(et C-style des tableaux, comme il arrive!).deque
en dépit d'être à accès aléatoire n'est pas contiguë (dangereusement, il est contiguë en petits morceaux!),list
n'est même pas proche, et le associatif (triées ou non) les conteneurs sont également non contigus.De sorte que les trois constructeurs j'ai mis en place où
std::array
,std::vector
et de style C tableaux, qui couvre l'essentiel des bases.La mise en œuvre de
[]
est facile, et entrefor()
et[]
qui est le plus de ce que vous voulez unarray
pour, n'est-ce pas?template
fonction avec d'un côté pas de détails de mise en œuvre. LeImpl
fonction n'est pas untemplate
fonction, et ainsi vous pouvez heureusement masquer la mise en œuvre dans le.cpp
fichier de votre choix. C'est vraiment un très brut de décoffrage de type effacement, où j'ai extrait la possibilité d'itérer sur contiguë de conteneurs dans une simplification de la classe, puis passer que par... (alors quemultArrayImpl
prend untemplate
comme un argument, ce n'est pas untemplate
lui-même).&*
déréférence l'itérateur (qui peut ne pas être un pointeur), puis fait un pointeur vers l'adresse. Pour mémoire contiguë de données, le pointeur debegin
et le pointeur vers un passé-laend
sont également des itérateurs à accès aléatoire, et ils sont du même type pour tous plage contiguë plus d'un type deT
.