2017-02-19 3 views
3

Comment puis-je transmettre un tableau temporaire? Je veux faire quelque chose comme ceci:Comment passer un tableau temporaire?

#include <iostream> 

int sum(int arr[]) { 
    int answer = 0; 
    for (const auto& i : arr) { 
     answer += i; 
    } 
    return answer; 
} 

int main() { 
    std::cout << sum({4, 2}) << std::endl;  // error 
    std::cout << sum(int[]{4, 2}) << std::endl; // error 
} 

Ai-je besoin d'un entier positif littérale dans les accolades du paramètre de la fonction []? Si j'inclus ce littéral, cela limitera-t-il les tableaux que je peux transmettre uniquement aux tableaux de cette taille? Aussi, comment puis-je passer des éléments de tableau par référence rvalue ou référence const? Parce que l'exemple ci-dessus ne compile pas, je suppose que la création du type de paramètre de la fonction int&&[] ou const int&[] ne fonctionnera pas.

+1

Vous pouvez utiliser un modèle pour en déduire la taille. –

+1

pourquoi ne pas utiliser 'std :: array' ou' std :: vector'? – Charles

+1

@ c650, je sais comment les utiliser. Je veux juste en apprendre davantage sur les tableaux de style C. – CodeBricks

Répondre

10

Tout d'abord, vous ne pouvez pas passer tableaux comme prvalues, donc votre fonction doit prendre une référence. Deuxièmement, la taille du tableau fait partie du type, donc votre fonction doit probablement faire partie d'un modèle. Troisièmement, l'écriture des temporaires de tableau est un peu stupide, donc vous avez besoin de bruit.

Mettre tous ensemble, ce qui suit devrait fonctionner

template <std::size_t N> 
int sum(const int (&a)[N]) 
{ 
    int n = 0; 
    for (int i : a) n += i; 
    return n; 
} 

int main() 
{ 
    using X = int[3]; 
    std::cout << sum(X{1, 2, 3}) << "\n"; 
} 

Le bruit syntaxique peut être généralisé légèrement avec un modèle d'alias:

template <std::size_t N> using X = int[N]; 

Utilisation: sum(X<4>{1, 2, 3, 4}) (Vous ne pouvez pas avoir le paramètre de modèle déduit de l'initialiseur.)

+1

[Démo] (https://ideone.com/VVXJr3). –

+0

Dans votre premier extrait, comment puis-je appeler la fonction sans la déclaration d'alias? – CodeBricks

+0

Ce modèle d'alias pour les tableaux existe déjà: 'std :: array {1, 2, 3}' – zett42

1

Je suggère de faire de la fonction de somme un modèle qui accepte n'importe quelle gamme au lieu de le limiter aux tableaux. De cette façon, vous pouvez utiliser la fonction avec des conteneurs standards comme std :: vector, std :: set ou même des conteneurs définis par l'utilisateur.

Ma solution nécessite la bibliothèque boost.range mais qui n'utilise pas de boost aujourd'hui? Les plages sont même considérées comme ajoutées à la bibliothèque standard.

#include <iostream> 
#include <array> 
#include <vector> 
#include <string> 
#include <boost/range.hpp> 
#include <initializer_list>  

template< typename Range > 
auto sum_impl(const Range& range) -> typename boost::range_value<Range>::type 
{ 
    typename boost::range_value<Range>::type result{}; 
    for(const auto& elem : range) 
     result += elem; 
    return result; 
} 

template< typename Range > 
auto sum(const Range& range) -> typename boost::range_value<Range>::type 
{ 
    return sum_impl(range); 
} 

template< typename Elem > 
Elem sum(const std::initializer_list<Elem>& range) 
{ 
    return sum_impl(range); 
} 

int main() 
{ 
    // Call the initializer_list overload 
    std::cout << sum({ 1, 2, 3 }) << "\n"; 
    std::cout << sum({ 1.0f, 2.1f, 3.2f }) << "\n"; 

    // Call the generic range overload 
    std::cout << sum(std::array<int,3>{ 1, 2, 3 }) << "\n"; 
    std::cout << sum(std::vector<float>{ 1.0f, 2.1f, 3.2f }) << "\n"; 
    std::cout << sum(std::vector<std::string>{ "a", "b", "c" }) << "\n"; 
} 

Quelques explications:

  • J'utilise auto comme type de retour juste pour faire la déclaration de fonction plus lisible. Vous pouvez aussi écrire comme ceci:

    typename boost::range_value<Range>::type sum(const Range& range)

  • Le modèle boost::range_value est utilisé pour déduire le type des éléments de la gamme. De cette façon, nous pouvons utiliser sum() non seulement pour ints, mais pour tout ce qui a un operator += défini! Vous pouvez voir dans mon exemple que nous pouvons même "ajouter" (concaténer) des chaînes ensemble. : D

  • La surcharge prenant un paramètre std::initializer_list rend finalement la syntaxe facile possible où nous pouvons appeler sum({ 1, 2, 3 }) comme demandé par l'OP.Cette surcharge est nécessaire, car la surcharge générique ne sera pas en déduire le type d'argument initializer_list (voir aussi initializer_list and template type deduction)

Démo:

http://coliru.stacked-crooked.com/a/80393e710fc355a6