могут ли функторы, вызываемые из алгоритмов, действующих на карте, принимать пару‹K, V› вместо value_type?

Я попытался написать короткую функцию для инвертирования std::map<K, V> (я знаю о boost.bimap, это для самообразования) и, к моему удивлению, обнаружил, что код, принятый GCC 4.4 с настройками -pedantic -ansi, был отклонен как const-incorrect SunCC (5.8, 2005 г.).

Поскольку value_type равно std::pair<const K, V>, SunCC настояла на том, чтобы я уточнил тип K в аргументах функций, которые передаются в transform() и for_each(), и в типе возвращаемого значения, которое должно быть передано в std::inserter, насколько я могу судить, это может быть прав? Какой компилятор соответствовал стандартам?

#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);
}

person Cubbi    schedule 04.10.2010    source источник
comment
Поддерживает ли эта версия компилятора Sun функции-шаблоны-члены? Если нет, это может объяснить отсутствие конструкторов неявного преобразования template<typename A,typename B> template<typename C,typename D> std::pair<A,B>::pair(const std::pair<C,D>&);.   -  person aschepler    schedule 04.10.2010
comment
@aschepler: Оказывается, этот конструктор #определен с помощью _RWSTD_NO_MEMBER_TEMPLATES в моей системе. Но та же самая программа компилируется с -library=stlport4, который получает другой набор включений. Сам компилятор ведь не виноват.   -  person Cubbi    schedule 04.10.2010


Ответы (1)


Visual C++ и g++ верны; этот код (где flip_pair<K, V>() принимает const std::pair<K, V>&) в порядке.

Внутри transform вызывается flip_pair<K, V>. Поскольку объект, передаваемый этой функции, является pair<const K, V>, создается временный объект типа pair<K, V> (pair имеет конструктор преобразования, который позволяет преобразовать один парный тип в другой, если типы .first и .second являются преобразуемыми).

Это временное значение передается flip_pair<K, V>(), используя тот факт, что константная ссылка может быть привязана к временному объекту.

person James McNellis    schedule 04.10.2010
comment
Разве создание временного pair<K,V> не отбрасывает квалификаторы const? Не было бы более подходящим просто квалифицировать тип как pair<const K, V> в этих функциях? - person JoshD; 04.10.2010
comment
@JoshD, компилятор не будет отбрасывать квалификаторы в типе. И типы в flip_pair‹K, V› будут следующими: flip_pair‹std::map‹K, V›::value_type::first_type, std::map‹K, V›::value_type::second_type›, которые будут расширяться на: flip_pair‹const std::map‹K, V›::key_type, std::map‹K, V›::mapped_type›. Другими словами, K является const K в реализации flip_pair в invert_map, поэтому дополнительный квалификатор const не нужен. - person MSN; 04.10.2010
comment
Как всегда просто! Совсем забыл об этом конструкторе, сбитый с толку ошибками «неправильного типа при создании экземпляра». - person Cubbi; 04.10.2010