Search code examples
c++boostvisual-studio-2019

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


Solution

  • 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