50 votes

Comment récupérer le type de valeur d'un itérateur en C++ ?

Ma question est certainement simple pour quiconque connaît la syntaxe C++. Je suis en train d'apprendre le C++ et c'est un peu en quelque sorte les devoirs.

template<typename Iter>
void quickSort(Iter begin, Iter end)
{        
    //..
    auto pivot = * ( begin + (end - begin)/2 );
    //..
}

pivot est censé contenir la valeur du centre de l'intervalle [begin, end] .

Le code que j'ai écrit ici fonctionne, mais auto est un mot clé de la nouvelle norme de langage C++11. Comment le faire à l'ancienne ? Que dois-je écrire à la place de auto ?

25 votes

C'est ce que j'aime voir. Quelqu'un qui vient d'apprendre le C++, utilisant des itérateurs et auto . :)

57voto

Steve Jessop Points 166970

typename std::iterator_traits<Iter>::value_type

Cela fonctionnera si votre modèle est instancié avec Iter comme un type de pointeur.

Au fait, typename ne fait pas partie du type lui-même. Il indique au compilateur que value_type est vraiment un type. S'il s'agissait du nom d'une fonction ou d'un membre de données statiques, alors cela affecte la syntaxe. Le compilateur ne sait pas nécessairement ce que c'est, puisque la spécialisation de iterator_traits para Iter peuvent ne pas être visibles lorsque le modèle est compilé.

1 votes

C'est la meilleure solution possible, mais il convient de souligner qu'il ne s'agit pas d'une solution générale. Il n'est pas garanti qu'elle fonctionne avec tout ce qu'un utilisateur pourrait essayer de passer comme itérateur... il se peut qu'il doive ajouter value_type à son objet itérateur (ou créer une spécialisation pour les traits). Une alternative est simplement de continuer à utiliser les itérateurs, et de créer un itérateur vers le pivot, en le déréférençant si nécessaire, sans avoir besoin du type de valeur dans la fonction modèle.

5 votes

@Tony : c'est vrai, et auto est meilleur pour cette raison. Cependant, tous les algorithmes standards requièrent que l'utilisateur passe quelque chose qui a iterator_traits (24.3.1), et il est raisonnable que les modèles de fonctions définies par l'utilisateur aient la même restriction. Les personnes qui écrivent des itérateurs peuvent utiliser std::iterator comme classe de base pour combler le fossé entre en essayant pour passer dans un itérateur, et en fait passer dans une Iterator ;-)

1 votes

@Tony, @Steve - voici une question de débutant, l'opérateur typeid() peut-il être utilisé ? Quelque chose comme type_info& ti = typeid(Iter) ;

6voto

Churianov Roman Points 58

Cela fonctionnera également à partir de c++ 11 :

typename Iter::value_type

Ainsi, vous n'avez pas à taper tout le std::iterator_traits chose.

0 votes

Cela ne fonctionnera pas si Iter est un type de pointeur brut.

2voto

David Tóth Points 1479

À partir de C++20, vous pouvez également utiliser la méthode suivante (accompagnée d'un exemple) :

#include <iostream>
#include <vector>

template<typename Iter>
void quickSort(Iter begin, Iter end)
{
    using T = std::remove_reference_t<std::iter_reference_t<Iter>>;
    //..
    T pivot = * ( begin + (end - begin)/2 );
    std::cout << "Element: " << pivot << std::endl;
    //..
}

int main(int argc, char* argv[]){
  std::vector<int> vec = {0,1,2,3,4,5};
  quickSort<std::vector<int>::iterator>(vec.begin(), vec.end());
  return 0;
}

sortie :

Element: 3

0voto

F. Mueller Points 9

La réponse de Steve est juste ; en C++98, vous devez utiliser std::iterator_traits ou vous pouvez utiliser Iter::value_type si vous savez que l'itérateur a ce typedef (par exemple, est dérivé de std::iterator). Cependant, il y a un autre problème dans votre code : vous ne pouvez normalement pas simplement diviser les itérateurs. Cela fonctionne avec les pointeurs, bien sûr, mais pas dans le cas plus général. Une approche plus générale serait :

Iter itPivot = std::advance(begin, std::distance(begin, end)/2);

1 votes

Le code original ne divise pas les itérateurs, et cela ne fonctionnerait pas, même avec des pointeurs. Le code utilise plutôt la soustraction, qui fonctionne sur tous les itérateurs à accès aléatoire (pas seulement les pointeurs). Et puisque quicksort sera trié pour les autres types d'itérateurs de toute façon (une implémentation efficace de toute façon), l'utilisation de operator - ici, c'est bien.

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