2010-10-08 4 views
2

Il est temps pour un autre 'comment faire cela en C++ sans perdre mon grip'-question!Conversion de tableaux dans stl comme copie

Cette fois-ci:

Vu le code ci-dessous du cplusplus.com:

template<class InputIterator, class OutputIterator> 
    OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) 
{ 
    while (first!=last) *result++ = *first++; 
    return result; 
} 

est-il un moyen de jeter *first le type de *result? En d'autres termes: existe-t-il un moyen de déterminer (au compiletime) le type de résultat?

Répondre

6

oui, le type de *result est (parce que le type de result est OutputIterator)

typename std::iterator_traits<OutputIterator>::value_type 

bien sûr, si OutputIterator est un pointeur ou un itérateur STL compatible correctement écrit. Sinon, non, je pense qu'il n'y a aucun moyen. Dans le prochain C++ 0x, il serait beaucoup plus facile, c'est

decltype(*result) 

HTH,

Armen

+0

Cela ne répond la moitié de la question (comment obtenir le type de valeur de l'itérateur de sortie, mais pas comment faire 'copy' effectuer la distribution sur tous les éléments – jalf

+0

grand qui en fait sauvé ma journée :) – fho

+0

jalf: Je pense que la première moitié de la question était un mauvais phrasé de la deuxième partie –

1

Pas une réponse précise à votre question, mais il semble que vous voulez ne veulent pas vraiment std::copy, vous voulez std::transform vos données à un autre type. Dans ce cas, faire quelque chose comme:

template <typename A, typename B> 
B convert(A x) { return static_cast<B>(x); } 

... 

std::transform(v1.begin(), v1.end(), v2.begin(), convert<float,int>); 
+0

et où avez-vous exactement déduit int et float à partir de? La question était, comme je l'ai compris, comment récupérer le type de valeur d'un itérateur dans le code générique. –

+1

@Armen: C'est un exemple! Évidemment, cela peut être paramétré plus génériquement. Le point de ma réponse est que vous n'avez pas besoin de réinventer la STL ... –

1

Vous pouvez modifier la routine de copie à utiliser un modèle pour faire le casting ...

template <typename A, typename B>            
const A& cast(const A&, const B& b)            
{                    
    return *reinterpret_cast<const A*>(&b);          
};                    

template <class InputIterator, class OutputIterator>        
OutputIterator mycopy(InputIterator first, InputIterator last,      
         OutputIterator result)          
{                    
    for (; first != last; ++first, ++result)         
     *result = cast(*result, *first);           
    return result;                
} 

Cela dit, Oli beaucoup mieux de la réponse de si vous n'êtes pas spécifiquement cherche à apprendre comment modifier la copie pour gérer cela ....

1

La réponse courte est non. Si OutputIterator est vraiment un OutputIterator (par exemple un ostream_iterator), puis: typename std :: iterator_traits :: value_type sera vide, et en C++ 0x, decltype (* résultat) est susceptible d'être OutputIterator. (La suggestion de So Armen ne fonctionne pas en code modèle.)

Et la suggestion de Tony impliquant reinterpret_cast ne fonctionne pas non plus . En fait, il va casser des choses qui fonctionnent (par exemple quand InputIterator retourne int, et OutputIterator veut double).

La seule vraie réponse est Oli. Ce qui est logique: ce que vous voulez vraiment faire, c'est transformer vos données, pas seulement les copier.

+0

1. "et en C++ 0x, decltype (* résultat) est susceptible d'être OutputIterator" Pourquoi? "2.Si OutputIterator est vraiment un OutputIterator (par exemple un ostream_iterator), alors ...". Eh bien, techniquement vous avez raison, mais on peut spécialiser l'iterator_traits pour output_iterator, n'est-ce pas? –

+0

Bien que la réponse d'Oli ne couvre pas comment il va déduire quel type de convertir à l'un ou l'autre. En ce qui concerne la spécialisation de 'iterator_traits', n'est-ce pas techniquement illégal (seules les spécialisations dans l'espace de noms std sont autorisées pour les types * définis par l'utilisateur)? - Mais vous pouvez créer vos propres traits d'itérateur, et spécialisez * that * pour 'ostream_iterator'. – UncleBens

+1

Vous n'êtes pas autorisé à spécialiser quoi que ce soit dans std ::, sauf si la spécialisation implique l'une de vos classes. Comment savez-vous que la mise en œuvre ne s'est pas déjà spécialisée? iterator_traits pour ostream_iterator, pour des raisons particulières de propres raisons? –

Questions connexes