navirius
navirius

Reputation: 317

boost::multi_index_container compiled with vs2008 but not with vs2019

I have multi index container like below

typedef Lock_<boost::mutex> DefaultLock;

template<class ADD_DATA>
struct ResourceRawData : private boost::noncopyable
{
   ResourceRawData(const TSTRING& pathFileName,bool bMustDirectory,const ADD_DATA& addData = ADD_DATA() )
   {    
   ...
   }
   ResourceRawData(const TSTRING& pathFileName,const TSTRING& strSettingName,bool bMustDirectory,const ADD_DATA& addData = ADD_DATA() )
   {
   ...
   }
}

template<class ADD_DATA>
class ResourceQueue : public DefaultLock , private boost::noncopyable
{
    typedef typename ResourceRawData< ADD_DATA > QUEUE_DATA;
    typedef typename boost::shared_ptr< QUEUE_DATA > SP_QUEUE_DATA;

    typedef boost::multi_index_container<
        SP_QUEUE_DATA,
        boost::multi_index::indexed_by<
            boost::multi_index::sequenced<>,
            boost::multi_index::hashed_unique< BOOST_MULTI_INDEX_CONST_MEM_FUN(QUEUE_DATA,const TSTRING&,GetFileName),string_hash >
        >
    > MULTI_INDEX_QUEUE;


    typedef typename MULTI_INDEX_QUEUE::nth_index<0>::type  QUEUE_INDEX_SEQUENCE; <<  error C2059: syntax error: '<'
    typedef typename MULTI_INDEX_QUEUE::nth_index<1>::type  QUEUE_INDEX_MAP;
}

error detail:

(322,47): error C2059: syntax error: '<'

(330): message : see reference to class template instantiation 'ResourceQueue<ADD_DATA>' being compiled

above code is compiled fine with visual studio 2008, but not with visual studio 2019, am I missing something? any usage standard changes with boost if I use with visual studio 2019?

thanks for help

Upvotes: 1

Views: 75

Answers (1)

sehe
sehe

Reputation: 392903

Two-phase lookup was recently fixed in MSVC. You might now run into a diagnostic that this use of typename was actually non-conformant (should never have compiled):

typedef typename ResourceRawData< ADD_DATA > QUEUE_DATA;

Just remove it

typedef ResourceRawData< ADD_DATA > QUEUE_DATA;

very similarly, the compiler will no longer wrongly accept unqualified template members on dependent types:

typedef typename MULTI_INDEX_QUEUE::nth_index<0>::type  QUEUE_INDEX_SEQUENCE;

You need to add template before the nested nth_index:

typedef typename MULTI_INDEX_QUEUE::template nth_index<0>::type  QUEUE_INDEX_SEQUENCE;
typedef typename MULTI_INDEX_QUEUE::template nth_index<1>::type  QUEUE_INDEX_MAP;

Now it compiles: GCC.

Now consider using type deduction to simplify a lot of the code:

MULTI_INDEX_QUEUE _queue;
auto& index_sequence() { return _queue.template get<0>(); }
auto& index_map()      { return _queue.template get<1>(); }

DEMO

Modernizing things and mocking some of the things left out:

Live On Coliru

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/thread.hpp>

using TSTRING = std::string;
using string_hash = boost::hash<TSTRING>;

// no idea really, just making this up:
template <typename M> struct Lock_ : boost::unique_lock<M> {
    Lock_() : boost::unique_lock<M>(_mx, boost::defer_lock) {}
    M _mx;
};

using DefaultLock = Lock_<boost::mutex>;

template <class ADD_DATA> struct ResourceRawData : private boost::noncopyable
{
    ResourceRawData(const TSTRING & pathFileName, bool /*bMustDirectory*/,
                    const ADD_DATA & addData = ADD_DATA())
        : _name(pathFileName), _value(addData) { }

    TSTRING const &GetFileName() const { return _name; }
    ADD_DATA const &GetValue() const { return _value; }

  private:
    TSTRING _name;
    ADD_DATA _value;
};

namespace bmi = boost::multi_index;

template <class ADD_DATA>
class ResourceQueue : public DefaultLock, private boost::noncopyable
{
    using QUEUE_DATA    = ResourceRawData<ADD_DATA>;
    using SP_QUEUE_DATA = boost::shared_ptr<QUEUE_DATA>;

    using MULTI_INDEX_QUEUE = bmi::multi_index_container<SP_QUEUE_DATA,
        bmi::indexed_by<
            bmi::sequenced<>,
            bmi::hashed_unique<
                ::bmi::const_mem_fun<QUEUE_DATA, const TSTRING &, &QUEUE_DATA::GetFileName>,
                string_hash>
            >
        >;

    MULTI_INDEX_QUEUE _queue;
    auto& index_map()                  { return _queue.template get<1>(); } 
    auto const& index_map()      const { return _queue.template get<1>(); } 
  public:
    auto& index_sequence()             { return _queue.template get<0>(); } 
    auto const& index_sequence() const { return _queue.template get<0>(); } 

    bool insert(TSTRING fname, ADD_DATA value)
    {
        return index_sequence()
            .push_back(
                boost::make_shared<QUEUE_DATA>(std::move(fname), false, value))
            .second;
    }

    ADD_DATA ValueByPath(TSTRING const &key) const
    {
        if (auto it = index_map().find(key); it != index_map().end())
        {
            return (*it)->GetValue();
        }
        else
        {
            return ADD_DATA{};
        }
    }
};

#include <iostream>

int main() {
    ResourceQueue<int> rq;
    assert(rq.insert("aaaa", 99));
    assert(rq.insert("bbbb", 42));
    assert(not rq.insert("aaaa", -1)); // not unique!
    assert(rq.insert("cccc", 100));

    std::cout << "index_sequence:\n";
    for (auto const &p : rq.index_sequence())
    {
        std::cout << p->GetFileName() << " -> " << p->GetValue() << "\n";
    }

    std::cout << "\nindex_map: " << rq.ValueByPath("bbbb") << "\n";
}

Prints

index_sequence:
aaaa -> 99
bbbb -> 42
cccc -> 100

index_map: 42

Upvotes: 1

Related Questions