2010-10-04 34 views
1

J'ai essayé d'écrire une courte fonction pour inverser un std::map<K, V> (je connais boost.bimap, c'est pour auto-éducation), et trouvé, à ma grande surprise, que le code que GCC 4.4 acceptait avec -pedantic -ansi paramètres était rejeté comme const-incorrect par SunCC (5.8, à partir de 2005).les foncteurs appelés à partir d'algorithmes agissant sur une carte peuvent-ils accepter la paire <K, V> au lieu de value_type?

Depuis value_type est std::pair<const K, V>, SunCC insisté pour que je le type const-mitiger mon K dans les arguments aux fonctions qui sont passés à transform() et for_each(), et dans le type de la valeur de retour à passer à std::inserter, pour autant que je peut dire, il pourrait être juste? Quel compilateur était conforme aux normes?

#include <iostream> 
#include <iterator> 
#include <map> 
#include <string> 
#include <algorithm> 
template<typename K, typename V> 
std::pair<V, K> flip_pair(const std::pair<K, V>& p) // GCC/MSVC 
//std::pair<const V, K> flip_pair(const std::pair<const K, V>& p) // SunCC 
{ 
    return std::make_pair(p.second, p.first); // GCC/MSVC 
//  return std::pair<const V, K>(p.second, p.first); // SunCC 
} 
template<typename K, typename V> 
std::multimap<V, K> invert_map(const std::map<K, V>& in) 
{ 
    std::multimap<V, K> out; 
    transform(in.begin(), in.end(), std::inserter(out, out.begin()), 
       flip_pair<K, V>); 
    return out; 
} 
void print_pair(const std::pair<int, std::string>& p) // GCC/MSVC 
//void print_pair(const std::pair<const int, std::string>& p) // SunCC 
{ 
     std::cout << p.first << '\t' << p.second << '\n'; 
} 
int main() 
{ 
    std::map<std::string, int> map; 
    map["foo"] = 1; map["bar"] = 2; map["baz"] = 3; 
    std::multimap<int, std::string> revmap = invert_map(map); 
    for_each(revmap.begin(), revmap.end(), print_pair); 
} 
+0

Cette version du modèle de membre de prise en charge du compilateur de Sun fonctionne-t-elle? Sinon, cela pourrait expliquer l'absence de constructeur de conversion implicite 'template template std :: pair :: pair (const std :: pair &);'. – aschepler

+0

@aschepler: Ce constructeur est # défini avec _RWSTD_NO_MEMBER_TEMPLATES sur mon système, il s'avère. Mais le même programme se compile avec '-library = stlport4', qui récupère un ensemble différent d'includes. Le compilateur lui-même n'est pas à blâmer, après tout. – Cubbi

Répondre

3

Visual C++ et g ++ sont corrects; ce code (avec flip_pair<K, V>() en prenant un const std::pair<K, V>&) est correct.

L'intérieur de transform, flip_pair<K, V> est appelé. Puisque l'objet transmis à cette fonction est un pair<const K, V>, un objet temporaire de type pair<K, V> est créé (pair a un constructeur de conversion qui vous permet de convertir un type de paire en un autre si les types .first et sont convertibles).

Ce temporaire est passé à flip_pair<K, V>(), en profitant du fait qu'une référence const peut être liée à un temporaire.

+0

Ne crée-t-il pas une "paire" temporaire 'élimine les qualificatifs const? Ne serait-il pas plus approprié de simplement qualifier le type de «paire » dans ces fonctions? – JoshD

+0

@JoshD, le compilateur ne supprimerait pas les qualificatifs dans le type. Et les types dans flip_pair seraient: flip_pair :: type_valeur :: premier_type, std :: carte :: type_valeur :: second_type> qui serait étendu à: flip_pair : : key_type, std :: map :: mapped_type>. En d'autres termes, K est const K dans l'instanciation de flip_pair dans invert_map, donc le qualificatif const additionnel est inutile. – MSN

+0

Simple comme toujours! J'ai tout oublié à propos de ce constructeur, confus par le «mauvais type lors de l'instanciation» des erreurs. – Cubbi