|
Boost Users : |
From: hirsch_at_[hidden]
Date: 2007-09-13 11:08:22
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
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net