【问题标题】:boost::multi_index_container compiled with vs2008 but not with vs2019boost::multi_index_container 用 vs2008 编译但不是用 vs2019
【发布时间】:2021-02-07 21:52:28
【问题描述】:

我有像下面这样的多索引容器

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

错误详情:

(322,47):错误 C2059:语法错误:'

(330): 消息:参见正在编译的类模板实例化“ResourceQueue”的参考

上面的代码在 Visual Studio 2008 中编译得很好,但在 Visual Studio 2019 中编译得不好,我错过了什么吗?如果我与 Visual Studio 2019 一起使用,使用标准是否会随着 boost 的变化而变化?

感谢帮助

【问题讨论】:

    标签: c++ boost visual-studio-2019


    【解决方案1】:

    最近在 MSVC 中修复了两阶段查找。您现在可能会遇到这样的诊断结果:typename 的这种使用实际上是不符合标准的(不应该编译):

    typedef typename ResourceRawData< ADD_DATA > QUEUE_DATA;
    

    删除它

    typedef ResourceRawData< ADD_DATA > QUEUE_DATA;
    

    非常相似,编译器将不再错误地接受依赖类型上的非限定模板成员:

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

    您需要在嵌套的nth_index之前添加template

    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;
    

    现在编译:GCC

    现在考虑使用类型推导来简化很多代码:

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

    演示

    使事物现代化并嘲笑一些被遗漏的事物:

    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";
    }
    

    打印

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

    【讨论】: