ошибка преобразования типа при использовании find () и modify () с boost MultiIndex - PullRequest
0 голосов
/ 16 марта 2020

По какой-то причине у меня есть несоответствие типов между итератором, возвращаемым функцией find (), и реализацией modify (), которую я использую для работы с ним. Мой код здесь и дословно воспроизведен здесь:

#include <iostream>
#include <string>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>

class Placeholder {
    public:
        const uint64_t& getPlaceholderTime( void )  const   { return ph_time; }
        const std::string& getPlaceholderId( void ) const   { return ph_id; }
        void setNewId( std::string& newId ) { ph_id = newId; }
        void setNewTime( uint64_t newTime ) { ph_time = newTime; }

    private:
        mutable uint64_t ph_time;
        std::string ph_id;
};

struct IndexByPlaceholderId { };

typedef boost::multi_index_container<
    Placeholder,
    boost::multi_index::indexed_by
    <boost::multi_index::ordered_non_unique< boost::multi_index::identity<Placeholder> >
    ,boost::multi_index::ordered_non_unique<
        boost::multi_index::const_mem_fun<
            Placeholder,
            const uint64_t&,
            &Placeholder::getPlaceholderTime
        >
    >
    ,boost::multi_index::ordered_non_unique<
        boost::multi_index::tag<IndexByPlaceholderId>,
        boost::multi_index::const_mem_fun<
            Placeholder,
            const std::string&,
            &Placeholder::getPlaceholderId
        >
    >
    >
> currentPlaceholderDatabase;

struct handlePlaceholderTransition {

    handlePlaceholderTransition( std::string& newId, uint64_t newTime )
    : newId_(newId)
    , newTime_(newTime)
    {
        std::cout << "NewId: " << newId << std::endl;
        std::cout << "NewTime: " << newTime << std::endl;
    }

    void operator()(Placeholder& ph)
    {
        ph.setNewId( newId_ );
        ph.setNewTime( newTime_ );
    }

    private:
        std::string newId_;
        uint64_t newTime_;
};

void lambdaHandlePlaceholderTransition( Placeholder& ph, std::string& newId, uint64_t newTime )
{
    ph.setNewId( newId );
    ph.setNewTime( newTime );
}

int main()
{
    static currentPlaceholderDatabase currentDb;

    std::string someString = "something";

    auto result = currentDb.get<IndexByPlaceholderId>().find( someString );
    if( result == currentDb.get<IndexByPlaceholderId>().end() )
    {
        std::cout << "NOT FOUND\n";
    }
    else
    {
        std::string newUpdatedId = "NEW_ID";
        currentDb.modify( result, handlePlaceholderTransition( newUpdatedId, 0 ) );
        /*
        currentDb.modify( result, [](Placeholder& ph) {
            std::cout << "Modifying Placeholder\n";
            std::string newUpdatedId = "NEW_ID";
            lambdaHandlePlaceholderTransition( ph, newUpdatedId, 0 );
        });
        */
        std::cout << "FOUND!!\n";
    }
}

Это приводит к ошибке, когда кажется, что итератор обернут в два дополнительных слоя преобразования шаблона order_index_node (я не уверен соответствующего языка, чтобы описать это):

/usr/include/boost/multi_index/ordered_index.hpp:434:8: note: template argument deduction/substitution failed: 
87:80: note: 
cannot convert 'result' (type 
'boost::multi_index::detail::bidir_node_iterator<
    boost::multi_index::detail::ordered_index_node<
        boost::multi_index::detail::index_node_base<
            Placeholder, 
            std::allocator<Placeholder> 
        > 
    > 
>') 

для ввода '... base_type_of_container ... :: iterator

{aka 
 boost::multi_index::detail::bidir_node_iterator<
    boost::multi_index::detail::ordered_index_node<
        boost::multi_index::detail::ordered_index_node<
            boost::multi_index::detail::ordered_index_node<
                boost::multi_index::detail::index_node_base<
                    Placeholder, 
                    std::allocator<Placeholder> 
                > 
            > 
        > 
    > 
>}' 

он также показывает, что эти типы похожи, за исключением дополнительные «уровни» упаковки шаблона. Этот пример основан на примере, показанном в документации MultiIndex при сравнении изменения с заменой, поэтому я затрудняюсь объяснить это.

Мои вопросы :

1.) Каков правильный синтаксис для передачи этого функтора, чтобы он успешно компилировался с использованием c ++ 11 и

2.) Могу ли я заменить функтор на эту лямбду, которая должна делать тоже самое? Я попытался заменить строку currentDb.modify () на этот фрагмент кода (как показано в комментариях выше), но получил ту же ошибку:

currentDb.modify( result, [](Placeholder& ph) {
    std::cout << "Modifying Placeholder\n";
    std::string newUpdatedId = "NEW_ID";
    lambdaHandlePlaceholderTransition( ph, newUpdatedId, 0 );
});

1 Ответ

0 голосов
/ 16 марта 2020

Вопрос 1. Проблема с вашим кодом состоит в том, что result является итератором для индекса # 2 (помеченного IndexByPlaceholderId), а currentdb.modify(...) ожидает, что итератор для индекса # 0. Вы можете переписать ошибочную строку следующим образом:

currentDb.get<IndexByPlaceholderId>().modify(
    result, handlePlaceholderTransition( newUpdatedId, 0 ) );

, если модификация выполняется по тому же индексу, к которому принадлежит итератор, или, альтернативно, как:

currentDb.modify(
    currentDb.project<0>(result), handlePlaceholderTransition( newUpdatedId, 0 ) );

, который использует проекция итератора для получения итератора индекса # 0 из result. Кстати, чтобы ваш фрагмент работал, вы должны определить operator< для Placeholder (так как индекс № 0 полагается на него).

Вопрос 2: Да, вы можете использовать лямбду и свои собственные Пример будет работать, как только вы решите проблему с итератором:

currentDb.modify( currentDb.project<0>(result), [](Placeholder& ph) {
    std::cout << "Modifying Placeholder\n";
    std::string newUpdatedId = "NEW_ID";
    lambdaHandlePlaceholderTransition( ph, newUpdatedId, 0 );
});
...