2014-01-15 3 views
2

Я пытаюсь заполнить boost::property_tree::ptree с Boost.Assign. Таким образом, я получил следующие прекрасно работали:Boost.Bind return type

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

Однако, когда я пытаюсь сделать этот код лучше выглядит, она не компилировать:

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

Сообщение об ошибке является

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

Что лучше всего сделать, чтобы код работал?

ответ

3

У вас есть несколько ошибок в коде:

  1. boost::bind() хранит связанные аргументы по значению, так что boost::bind(&bpt::ptree::put<std::string>, pt, _1, _2) делает копию pt и заполняет эту копию. Пропустите указатель вместо: boost::bind(&bpt::ptree::put<std::string>, &pt, _1, _2) или используйте boost::ref(pt).
  2. Объекты, возвращаемые boost::bind, не могут быть переведены в тип указателя, поэтому PutType putFunction = boost::bind(Put, pt, _1, _2); не удается скомпилировать.

В C++ 03 без auto ключевого слова вы не можете легко захватить типы boost::bind и boost::list_inserter. Вы могли бы обернуть результаты обоих в boost::function<>, но это было бы слишком тяжело, на мой взгляд.

Но вы можете достичь желаемого синтаксиса в C++ 03 с простым:

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"); 
} 
+0

Спасибо (+1). Вы знаете, как я могу переписать код, чтобы он работал? – Loom

+0

Еще раз спасибо. Почему 'boost :: function' тяжело? Есть ли какие-то штрафы за производительность? – Loom

+1

@Loom 'boost :: function' включает выделение памяти при построении и копировании; и указатель-указатель при вызове. Он оптимизирован для некоторых простых случаев, чтобы избежать выделения памяти, хотя это не такие случаи. –