Получение указателя или ссылки на mapped_type из произвольной карты - PullRequest
1 голос
/ 28 августа 2011

Редактировать: Я нашел и написал решение своей проблемы, но оставил вопрос без ответа, поскольку мое решение все еще может быть не идеальным.

Я пишунебольшая библиотека, предназначенная для выполнения подпрограмм на картах карт, но у меня возникают проблемы при разработке набора шаблонов классов, которые позволят мне получить указатель или ссылку (в зависимости от second_type для value_type карты) на mapped_type карты, независимо оттип карты (например, std :: map, boost :: ptr_map).

Для более подробного описания я перечислил некоторые типы ввода и нужные типы вывода.

Case   Input Type                                   Output Type
 A     std::map<int, std::map<int, int> >           std::map<int, int>&
 B     std::map<int, boost::ptr_map<int, int> >     boost::ptr_map<int, int>&
 C     boost::ptr_map<int, std::map<int, int> >     std::map<int, int>* const
 D     std::map<int, std::map<int, int> >*          std::map<int, int>&
 E     std::map<int, boost::ptr_map<int, int> >*    boost::ptr_map<int, int>&
 F     boost::ptr_map<int, std::map<int, int> >*    std::map<int, int>* const

Мой кодпропускает случаи A, B, D и E, но терпит неудачу в случаях C и F. Вот что я имею до сих пор.

template <class Map>
struct map_utils
{
    template <class K>
    static typename
    boost::remove_pointer<
            typename Map::value_type
    >::type::second_type&
    get(Map& m, const K k)
    {
            return m[k];
    }

    template <class K>
    static typename
    boost::remove_pointer<
            typename Map::value_type
    >::type::second_type&
    get(const Map& m, const K k)
    {
            return const_cast<Map&>(m)[k];
    }
};

template <class Map>
struct map_utils<Map*>
{
    template <class T>
    static typename
    boost::remove_pointer<
            typename Map::value_type
    >::type::second_type&
    get(Map* m, const T t)
    {
            return (*m)[t];
    }

    template <class T>
    static typename
    boost::remove_pointer<
            typename Map::value_type
    >::type::second_type&
    get(const Map* m, const T t)
    {
            return const_cast<Map*>(m)->operator[](t);
    }
};

Я пытаюсь использовать для этого boost :: mpl, иэто то, что я до сих пор готовил, но я получаю одну и ту же ошибку, используя обе версии кода.

Ошибка.

error: invalid initialization of reference of type ‘std::map<int, double>* const&’ from         expression of type     ‘boost::ptr_container_detail::reversible_ptr_container<boost::ptr_container_detail::map_config<std::map<int, double>, std::map<int, void*, std::less<int>, std::allocator<std::pair<const int, void*> > >, true>, boost::heap_clone_allocator>::Ty_’

Измененная специализация структуры для обработкис l-значениями, которые не являются указателями на карты.

template <class K>
    static typename
    boost::mpl::if_<
            boost::is_pointer<
                    typename boost::remove_pointer<
                            typename Map::value_type
                    >::type::second_type
            >,
            typename boost::remove_pointer<
                    typename boost::remove_const<
                            typename Map::value_type
                    >::type
            >::type::second_type,
            typename boost::remove_pointer<
                    typename Map::value_type
            >::type::second_type&
    >::type
    get(Map& m, const K k)
    {
            return m[k];
    }

Ответы [ 2 ]

1 голос
/ 28 августа 2011

C и F кажутся неправильными, сопоставленный тип не является boost :: ptr_map. В противном случае кажется, что вы можете просто использовать полную специализацию шаблона, чтобы решить, является ли это std :: map или boost :: ptr_map. Примерно так:

template <class Map>
class Whatever;

template <class K, class V>
class Whatever<std::map<K, V> >
{
    public:
        typedef V& Type;
};

template <class K, class V>
class Whatever<std::map<K, V>* >
{
    public:
        typedef V& Type;
};

template <class K, class V>
class Whatever<boost::ptr_map<K, V> >
{
    public:
        typedef V* const Type;
};

template <class K, class V>
class Whatever<boost::ptr_map<K, V>* >
{
    public:
        typedef V* const Type;
};
0 голосов
/ 28 августа 2011

Я успешно получил код для компиляции и значительно упростил его, используя made_type typedef примерно так:

template <class K>
static typename boost::remove_pointer<
        typename Map::mapped_type
>::type&
get(Map& m, const K k)
{
        return m[k];
}

В специализированных версиях нужно изменять только тело методовструктуры, определенной в вопросе выше, для размещения указателей на карты.Если вам нужен полный листинг кода, дайте мне знать, и я напишу все это здесь.

...