150 votes

Passer un std::array de taille inconnue à une fonction

En C++11, comment dois-je m'y prendre pour écrire une fonction (ou une méthode) qui prend un std::array de type connu mais de taille inconnue ?

// 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 mes recherches, je n'ai trouvé que des suggestions d'utilisation de modèles, mais ceux-ci semblent désordonnés (définitions de méthodes dans l'en-tête) et excessifs pour ce que j'essaie d'accomplir.

Existe-t-il un moyen simple de faire fonctionner cela, comme on le ferait avec des tableaux de style C ?

130voto

Andy Prowl Points 62121

Existe-t-il un moyen simple de faire fonctionner cela, comme on le ferait avec des tableaux de style C ?

Non. Vous ne pouvez vraiment pas le faire à moins de faire de votre fonction une fonction modèle (ou utilisez une autre sorte de conteneur, comme un std::vector (comme suggéré dans les commentaires de la question) :

template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
    for(auto& e : arr) {
        e *= multiplier;
    }
}

Voici un exemple concret .

36voto

Mark B Points 60200

La taille de la array es partie du type donc vous ne pouvez pas faire tout à fait ce que vous voulez. Il y a quelques alternatives.

Le mieux serait de prendre une paire d'itérateurs :

template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
    for(; first != last; ++first) {
        *first *= multiplier;
    }
}

Vous pouvez également utiliser vector au lieu de tableau, ce qui vous permet de stocker la taille au moment de l'exécution plutôt que de l'intégrer à son type :

void mulArray(std::vector<int>& arr, const int multiplier) {
    for(auto& e : arr) {
        e *= multiplier;
    }
}

19voto

suncho Points 121

EDITAR

C++20 comprend provisoirement std::span

https://en.cppreference.com/w/cpp/container/span

Réponse originale

Ce que vous voulez, c'est quelque chose comme gsl::span qui est disponible dans la bibliothèque de soutien aux directives décrite dans les directives de base C++ :

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views

Vous pouvez trouver une implémentation open-source de la GSL en en-tête seulement ici :

https://github.com/Microsoft/GSL

Avec gsl::span vous pouvez le faire :

// made up example
void mulArray(gsl::span<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);

Le problème avec std::array est que sa taille fait partie de son type, ce qui signifie que vous devez utiliser un modèle pour implémenter une fonction qui prend un fichier std::array de taille arbitraire.

gsl::span d'autre part, stocke sa taille en tant qu'information d'exécution. Cela vous permet d'utiliser une fonction non-modèle pour accepter un tableau de taille arbitraire. Elle acceptera également d'autres conteneurs contigus :

std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};

mulArray(vec, 6);
mulArray(carr, 7);

Plutôt cool, hein ?

8voto

musk's Points 93

J'ai essayé ci-dessous et ça a marché pour moi.

#include <iostream>
#include <array>

using namespace std;

// made up example
void mulArray(auto &arr, const int multiplier) 
{
    for(auto& e : arr) 
    {
        e *= multiplier;
    }
}

void dispArray(auto &arr)
{
    for(auto& e : arr) 
    {
        std::cout << e << " ";
    }
    std::cout << endl;
}

int main()
{

    // lets imagine these being full of numbers
    std::array<int, 7> arr1 = {1, 2, 3, 4, 5, 6, 7};
    std::array<int, 6> arr2 = {2, 4, 6, 8, 10, 12};
    std::array<int, 9> arr3 = {1, 1, 1, 1, 1, 1, 1, 1, 1};

    dispArray(arr1);
    dispArray(arr2);
    dispArray(arr3);

    mulArray(arr1, 3);
    mulArray(arr2, 5);
    mulArray(arr3, 2);

    dispArray(arr1);
    dispArray(arr2);
    dispArray(arr3);

    return 0;
}

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

7voto

Absolument, il existe un moyen simple en C++11 d'écrire une fonction qui prend un std::array de type connu, mais de taille inconnue.

Si nous ne sommes pas en mesure de transmettre la taille du tableau à la fonction, nous pouvons alors transmettre l'adresse mémoire du début du tableau ainsi qu'une deuxième adresse de la fin du tableau. Plus tard, à l'intérieur de la fonction, nous pouvons utiliser ces 2 adresses mémoire pour calculer la taille du tableau !

#include <iostream>
#include <array>

// The function that can take a std::array of any size!
void mulArray(int* piStart, int* piLast, int multiplier){

     // Calculate the size of the array (how many values it holds)
     unsigned int uiArraySize = piLast - piStart;

     // print each value held in the array
     for (unsigned int uiCount = 0; uiCount < uiArraySize; uiCount++)     
          std::cout << *(piStart + uiCount) * multiplier << std::endl;
}

int main(){   

     // initialize an array that can can hold 5 values
     std::array<int, 5> iValues{ 5, 10, 1, 2, 4 };

     // Provide a pointer to both the beginning and end addresses of 
     // the array.
     mulArray(iValues.begin(), iValues.end(), 2);

     return 0;
}

Sortie sur la console :

10, 20, 2, 4, 8

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X