духовная карма: доступ к некопируемому указателю

Я пытаюсь получить доступ к вектору указателей в моей грамматике кармы без особого успеха. Тип указателя не копируется, поэтому использующее его правило должно принимать ссылку:

#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace karma = boost::spirit::karma;
namespace fusion = boost::fusion;
namespace phx = boost::phoenix;

struct test1 : boost::noncopyable {
  test1(int i = 0) : value(i) {}
  int value;
};

struct test2 : boost::noncopyable {
  int value;
  std::vector<test1*> vector;
};

BOOST_FUSION_ADAPT_STRUCT( test1, (int, value) );
BOOST_FUSION_ADAPT_STRUCT( test2, (int, value) (std::vector<test1*>, vector) );

typedef std::ostream_iterator<char> Iterator;

int main() {

  karma::rule<Iterator, test1*()> t1r;
  karma::rule<Iterator, test2&()> t2r;

  t2r %= "test 2 rule:" << karma::int_ << karma::eol << (t1r % karma::eol);
  t1r %= "test 1 rule: " << karma::int_;

  std::stringstream stream;
  std::ostream_iterator<char> out(stream);

  test2 t;
  t.vector.push_back(new test1(2));
  t.vector.push_back(new test1(3));
  t.vector.push_back(new test1(4));
  t.vector.push_back(new test1(5));
  t.value = 1;

  karma::generate(out, t2r, t);      
  std::cout<<stream.str()<<std::endl;
}

Это компилируется, но возвращает: правило проверки 2:1, правило проверки 1: 25104656, правило проверки 1: 25104720 и так далее. Я знаю, что в этом простом случае я мог бы сделать

t1r = "test 1 rule: " << karma::int_[karma::_1 = phx::bind(&test1::value, *karma::_val)];

чтобы решить эту проблему, но на самом деле value — это еще один некопируемый тип, который должен быть передан в грамматику, и поэтому мне нужно использовать адаптацию структуры, как это сделано в примере.

Я также знаю о точке настройки deref_iterator, как уже упоминалось здесь , однако я работаю над библиотекой шаблонов и не думаю, что можно специализировать deref_iterator с типом, зависящим от шаблона.

Любые идеи о том, как заставить пример работать?


person ickby    schedule 16.03.2013    source источник
comment
Я не знаю, лучший ли это способ сделать это, но это похоже работает. И, в отличие от deref_iterator, его очень просто частично специализировать, например этот (обратите внимание, что это по-видимому, невозможно адаптировать шаблонные структуры, которые имеют параметры шаблона, отличные от типа, с помощью BOOST_FUSION_ADAPT_TPL_STRUCT)   -  person    schedule 16.03.2013
comment
@llonesmiz ты собираешься сделать это привычкой? Я имею в виду, что вы могли бы также поднять весь комментарий до ответа, и я был бы рад расширить его, когда найду. Если я думаю, что действительно добавлю что-то другое, я просто добавлю свой собственный ответ   -  person sehe    schedule 17.03.2013
comment
Что ж, спасибо IIonesmiz, похоже, это работает. Портирую его на мой код сейчас! Как я могу принять ваш комментарий в качестве ответа? Или я должен сам опубликовать решение в качестве ответа?   -  person ickby    schedule 17.03.2013
comment
@ickby Если вы поставите это как ответ, я проголосую за него. Но я хочу повторить, что я не знаю, действительно ли это лучший способ. Может быть, sehe поставит ответ в будущем.   -  person    schedule 17.03.2013
comment
Я полностью поддерживаю первый комментарий в качестве ответа.   -  person sehe    schedule 18.03.2013


Ответы (1)


llonesmiz ответил на мой вопрос в комментариях, поэтому я публикую его внутренности для будущих ссылок. Используя точку настройки transform attribute, проблему можно решить следующим образом:

#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace karma = boost::spirit::karma;
namespace fusion = boost::fusion;
namespace phx = boost::phoenix;

template <typename Value1, typename Value2>
struct test1 : boost::noncopyable {
  test1(Value1 i = Value1(), Value2 j = Value2() ): value1(i),value2(j) {}
  Value1 value1;
  Value2 value2;
};

struct test2 : boost::noncopyable {
  int value;
  std::vector<test1<int,double>*> vector;
};

BOOST_FUSION_ADAPT_TPL_STRUCT(
(Value1)(Value2),
(test1) (Value1)(Value2),
(Value1, value1)
(Value2, value2))

typedef std::vector<test1<int,double>*> test1_vector;

BOOST_FUSION_ADAPT_STRUCT( test2, (int, value) (test1_vector, vector) )

typedef std::ostream_iterator<char> Iterator;

namespace boost { namespace spirit { namespace traits
{
template <typename Value1, typename Value2>
struct transform_attribute<test1<Value1,Value2>* const, test1<Value1,Value2>&, karma::domain>
{
    typedef test1<Value1,Value2>& type;
    static type pre(test1<Value1,Value2>* const& val) 
    { 
      return *val; 
    }
};
}}}

int main() {

  karma::rule<Iterator, test1<int,double>*()> t1r;
  karma::rule<Iterator, test2&()> t2r;

  t2r %= "test 2 rule:" << karma::int_ << karma::eol << (t1r % karma::eol);
  t1r %= "test 1 rule: " << karma::attr_cast<test1<int,double>*,test1<int,double>&>(karma::delimit(karma::space)[karma::int_<< karma::double_]);

  std::stringstream stream;
  std::ostream_iterator<char> out(stream);

  test2 t;
  t.vector.push_back(new test1<int,double>(2));
  t.vector.push_back(new test1<int,double>(3));
  t.vector.push_back(new test1<int,double>(4));
  t.vector.push_back(new test1<int,double>(5));
  t.value = 1;

  karma::generate(out, t2r, t);      
  std::cout<<stream.str()<<std::endl;
}
person ickby    schedule 19.03.2013
comment
Другой вариант с использованием deref_iterator. Я надеялся, что это будет лучшее решение, но, как видите... это не так. - person ; 20.03.2013