35 votes

passer une référence à un tableau en C++

Quelqu'un peut-il m'aider à comprendre le code suivant

#include <iostream>

void foo(const char * c)
{
   std::cout << "const char *" << std::endl;
}

template <size_t N>
void foo(const char (&t) [N])
{
   std::cout << "array ref" << std::endl;
   std::cout << sizeof(t) << std::endl;
}

int main()
{
    const char t[34] = {'1'};
    foo(t);

    char d[34] = {'1'};
    foo(d);
}

Le résultat est

const char *
array ref
34

Pourquoi le premier foo appelle-t-il le const char * version ? Comment faire pour qu'il appelle la version de référence ?

15voto

Conversion de const char[N] à const char* est considérée comme une "correspondance exacte" (pour faciliter les littéraux, principalement), et entre deux correspondances exactes, une fonction non-modèle est prioritaire.

Vous pouvez utiliser enable_if y is_array pour le forcer à faire ce que vous voulez.


Une façon désordonnée de le forcer pourrait être :

#include <iostream>

template <typename T>
void foo(const T* c)
{
   std::cout << "const T*" << std::endl;
}

template <typename T, size_t N>
void foo(const T (&t) [N])
{
   std::cout << "array ref" << std::endl;
}

int main()
{
    const char t[34] = {'1'};
    foo(t);

    char d[34] = {'1'};
    foo(d);
}

/*
array ref
array ref
*/

Je réalise que le PO avait char pas un générique T mais cela démontre néanmoins que le problème réside dans le fait qu'une surcharge est un modèle et pas l'autre.

5voto

aschepler Points 23731

Examinons cet exemple modifié, sans modèle.

void foo(const char * c)
{
    std::cout << "const char *" << std::endl;
}

void foo(const char (&t) [34])
{
    std::cout << "const char (&) [34]" << std::endl;
}

int main()
{
    const char t[34] = {'1'};
    foo(t);
}

Mon compilateur dit que l'appel d'une surcharge foo est ambiguë. Cela est dû au fait que les conversions de tableau à pointeur sont considérées comme une séquence de conversion "exacte" et ne sont pas meilleures que la séquence de conversion nulle pour la résolution des surcharges (section 13.3.3.1.1 de la norme).

Dans le code original, le paramètre du modèle N peut être déduit comme 34, mais alors les deux non-template foo(const char*) y foo<34>(const char (&)[34]) sont prises en compte dans la résolution des surcharges. Comme aucune n'est meilleure que l'autre selon les règles de conversion, la fonction non-modèle bat la fonction modèle.

Réparer les choses semble délicat. Il semble que le is_array modèle de l'en-tête <type_traits> (de C++0x si possible ou de Boost sinon) pourrait aider.

1voto

Millianz Points 86

Cela semble être différent pour les différents compilateurs.

Mircosoft et Borland utilisent tous deux la version const char*, tandis que GNU donne le résultat que vous avez décrit.

Voici un extrait de la norme C++ :

14.8.2.1 Déduire les arguments du modèle à partir d'un appel de fonction [temp.deduct.call]

La déduction des arguments du modèle est effectuée par en comparant chaque modèle de fonction (appelé P) avec le type de paramètre type de l'argument correspondant de l'appel (appelé A) comme décrit ci-dessous.

Si P n'est pas un type de référence :

-- Si A est un type de tableau, le type de pointeur produit par la méthode array-to-pointer standard (4.2) est utilisée à la place de à la place de A pour la déduction de type ; sinon,

-- Si A est un type de fonction, le type de pointeur produit par le standard norme fonction-pointeur (4.3) est utilisé à la place de A pour la déduction de type ; sinon,

-- Si A est un type qualifié cv, les qualificateurs cv de niveau supérieur du type de A sont ignorés pour la déduction du type.

Si P est un type qualifié cv, le haut de page de niveau supérieur du type de P sont ignorés pour la déduction de type. Si P est un type de référence, le type auquel fait référence par P est utilisé pour la déduction de type

Le compilateur va construire un A comme suit :

Argument:        t                 d
A:          char const[34]      char[34]

Et la liste des paramètres P :

Parameter:       c                 t
P:            char const*       char const& t[N]

Par défaut, le compilateur doit choisir des paramètres non référencés. Pour une raison quelconque, GNU se trompe la deuxième fois.

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