2
votes

I'm trying to fill boost::property_tree::ptree with Boost.Assign. So, I got the following worked fine:

namespace bpt = boost::property_tree;
bpt::ptree pt;
boost::assign::make_list_inserter
    (boost::bind(&bpt::ptree::put<std::string>, pt, _1, _2))
        ("one.two.three", "four")
        ("one.two.five", "six");

However, when I trying to make this code better looking, it fails to compile:

typedef bpt::ptree& (bpt::ptree::*PutType)
    (const bpt::path_of<std::string>::type&, const std::string &);

PutType Put = &bpt::ptree::put<std::string>;

inline boost::assign::list_inserter<PutType> put(bpt::ptree &pt) {
  PutType putFunction = boost::bind(Put, pt, _1, _2); // !!! compile error
  return boost::assign::make_list_inserter(putFunction);
}

//and use it like:
put(pt)
    ("one.two.three", "four")
    ("one.two.five", "six");

Error message is

SomeFile.cpp: In function ‘boost::assign::list_inserter<boost::property_tree::ptree& (boost::property_tree::ptree::*)(const boost::property_tree::string_path<std::string, boost::property_tree::id_translator<std::string > >&, const std::string&), boost::assign_detail::forward_n_arguments> put(boost::property_tree::ptree&)’:

SomeFile.cpp:42: error: cannot convert ‘boost::_bi::bind_t<boost::property_tree::ptree&, boost::_mfi::mf2<boost::property_tree::ptree&, boost::property_tree::ptree, const boost::property_tree::string_path<std::string, boost::property_tree::id_translator<std::string > >&, const std::string&>, boost::_bi::list3<boost::_bi::value<boost::property_tree::ptree >, boost::arg<1>, boost::arg<2> > >’ to ‘boost::property_tree::ptree& (boost::property_tree::ptree::*)(const boost::property_tree::string_path<std::string, boost::property_tree::id_translator<std::string > >&, const std::string&)’ in initialization

What is best way to make it code worked?

1

1 Answers

3
votes

You have a couple of errors in the code:

  1. boost::bind() stores bound arguments by value, so that boost::bind(&bpt::ptree::put<std::string>, pt, _1, _2) makes a copy of pt and fills that copy. Pass a pointer instead: boost::bind(&bpt::ptree::put<std::string>, &pt, _1, _2) or use boost::ref(pt).
  2. The objects returned by boost::bind cannot be cast to a pointer type, this is why PutType putFunction = boost::bind(Put, pt, _1, _2); fails to compile.

In C++03 without auto keyword you cannot easily capture the types of boost::bind and boost::list_inserter. You could wrap the results of both into boost::function<> but that would be too heavy-handed, in my opinion.

But you can achieve the desired syntax in C++03 with plain:

namespace bpt = boost::property_tree;

struct PtreeInserter
{
    bpt::ptree* pt;

    PtreeInserter(bpt::ptree& pt) : pt(&pt) {}

    template<class A1, class A2>
    PtreeInserter const& operator()(A1 a1, A2 a2) const {
        pt->put(a1, a2);
        return *this;
    }
};

int main() {
    bpt::ptree pt;
    typedef PtreeInserter put;
    put(pt)
        ("one.two.three", "four")
        ("one.two.five", "six");
}