views:

40

answers:

1

I tried to write a short function to invert an std::map<K, V> (I know about boost.bimap, this is for self-education), and found, to my surprise, that the code that GCC 4.4 accepted with -pedantic -ansi settings was rejected as const-incorrect by SunCC (5.8, from 2005).

Since value_type is std::pair<const K, V>, SunCC insisted that I const-qualify my K type in the arguments to functions that are passed to transform() and for_each(), and in the type of the return value to be passed to std::inserter, as far as I can tell, it might be right? Which compiler was standards-compliant?

#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);
}
+3  A: 

Visual C++ and g++ are correct; this code (with flip_pair<K, V>() taking a const std::pair<K, V>&) is okay.

Inside of transform, flip_pair<K, V> is being called. Since the object being passed to that function is a pair<const K, V>, a temporary object of type pair<K, V> is created (pair has a converting constructor that allows you to convert one pair type to another if the .first and .second types are convertible).

This temporary is passed to flip_pair<K, V>(), taking advantage of the fact that a const reference can be bound to a temporary.

James McNellis
Doesn't creating a temporary `pair<K,V>` discard const qualifiers? Wouldn't it be more appropriate to just qualify the type as `pair<const K, V>` in those functions?
JoshD
@JoshD, the compiler would not discard qualifiers in the type. And the types in flip_pair<K, V> would be: flip_pair<std::map<K, V>::value_type::first_type, std::map<K, V>::value_type::second_type> which would expand out to: flip_pair<const std::map<K, V>::key_type, std::map<K, V>::mapped_type>. In other words, K is const K in the instantiation of flip_pair in invert_map, so the additional const qualifier is unnecessary.
MSN
Simple as always! Forgot all about that constructor, confused by the 'wrong type while instantiating' errors.
Cubbi
Ah, OK. Thanks for clearing up my confusion.
JoshD