[variant] Accessor class for recursive variant type
Hi, I have a recursive variant type like that: -------------------------- typedef boost::make_recursive_variant<bool, int, double, std::string, std::vector< boost::recursive_variant_ >, std::map<std::string, boost::recursive_variant_> >::type TVType; typedef std::vector<TVType> TVector; typedef std::map<std::string, TVType> TMap; -------------------------- And I implemented an accessor class to extract elements from the variant in a path-linke manner: -------------------------- TMap map; map["longValue"] = 23; map["stringValue"] = "abcde"; TVector subvec; subvec.push_back(42); map["subVector"] = subvec; TVType tv = map; Access acc(tv); std::string sValue = acc.get<std::string>("stringValue"); // "abcde" long nSubValue = acc.get<long>("subVector/0"); // 42 ---------------------------- It is implemented by using a boost::static_visitor. It works fine for now, but I also want to change values which are inside my variant hierarchy. So I have to return a reference-type from my Access helper rather than a value type, but I can't figure out how to do this. Here's the implementation of the accessor as it is now: ---------------------------- class Access: public boost::static_visitor<TVType> { typedef std::list< std::string > TStrList; public: template<typename T> T get(const std::string& sPath, const TVType& tvt) { m_aSplits.clear(); // split the path-parts, neighboring splitters will be // automatically compressed to one. boost::split( m_aSplits, sPath, std::bind2nd( std::equal_to<char>(), '/'), boost::token_compress_on); // remove empty entries for(TStrList::iterator it = m_aSplits.begin(); it!= m_aSplits.end(); ++it) { if(it->empty()) it = m_aSplits.erase(it); } // in case of an exception, transform the boost::bad_get exception to our CIS::Exception try { return boost::get<T>(boost::apply_visitor(*this, tvt)); } catch(boost::bad_get& ex) { throw CIS::Exception(ex.what(), EX_POS); } } TVType operator()(const TVector& v) { // if the splits-list is empty we have found our element, so the TVector itself was requested if(m_aSplits.empty()) return v; const uint32_t nIdx = boost::lexical_cast<uint32_t>(m_aSplits.front()); if(nIdx >= v.size()) throw Exception(boost::format("Invalid index: '%1%' from '%2%' in access path") % nIdx % v.size(), EX_POS); m_aSplits.pop_front(); return boost::apply_visitor(*this, v[nIdx]); } TVType operator()(const TMap& m); { // if the splits-list is empty we have found our element, so the TMap itself was requested if(m_aSplits.empty()) return m; TMap::const_iterator it = m.find(m_aSplits.front()); if(it == m.end()) throw Exception(boost::format("Invalid key: '%1%' in access path") % m_aSplits.front(), EX_POS); m_aSplits.pop_front(); return boost::apply_visitor(*this, it->second); } template<typename T> TVType operator()(const T& t) { return t; } private: TStrList m_aSplits; ///< splitted parts of the path. }; ------------------------ I tried to remove the consts and return a reference, but the compiler claims it can't convert a TVector& to a TVType&. I also tried with pointers but got the same error. Does anybody have an ide how I can implement this functionality? Thanks, Falco
participants (1)
-
hirsch@bigfoot.de