2016-06-20 5 views
3

У меня есть следующий фрагмент кода, который, кажется, работает нормально (я основывал семантические действия на reuse parsed variable with boost karma).Boost karma: как работает этот неявный вызов transform_attribute? (или нет?)

#include <iostream> 
#include <iterator> 
#include <memory> 
#include <string> 
#include <vector> 

#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/fusion/include/sequence.hpp> 
#include <boost/spirit/include/karma.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/spirit/include/phoenix_fusion.hpp> 
#include <boost/spirit/include/phoenix_bind.hpp> 
#include <boost/spirit/include/support_attributes.hpp> 
#include <boost/spirit/include/support_adapt_adt_attributes.hpp> 

using namespace boost::spirit; 

struct DataElement 
{ 
    DataElement(const std::string& s) : str_(s) {} 

    const std::string& str() const { return str_; } 
    std::string& str() { return str_; } 
    std::string str_; 
}; 
using Data = std::vector<std::shared_ptr<const DataElement>>; 

namespace boost { 
    namespace spirit { 
    namespace traits { 

     template<> 
     struct transform_attribute<std::shared_ptr<const DataElement> const, const DataElement&, karma::domain> 
     { 
     using type = const DataElement&; 
     static type pre(const std::shared_ptr<const DataElement>& val) { return *val; } 
     }; 

    } 
    } 
} 

BOOST_FUSION_ADAPT_ADT(
    DataElement, 
    (std::string&, const std::string&, obj.str(), obj.str()) 
); 

template<typename Iterator> 
struct TheGrammar: public karma::grammar<Iterator, Data()> 
{ 
    TheGrammar(): karma::grammar<Iterator, Data()>(start) 
    { 
    start %= -(elt % karma::eol); 
    elt %= 
     karma::lit("'some prefix'") 
     << karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)] 
     << karma::lit("'some infix 1'") 
     << karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)] 
     << karma::lit("'some infix 2'") 
     << karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)] 
     << karma::lit("'some suffix'") 
     ; 
    } 

    karma::rule<Iterator, Data()> start; 
    karma::rule<Iterator, const DataElement&()> elt; 
}; 

int main(void) 
{ 
    Data vec = { 
    std::make_shared<DataElement>("one"), 
    std::make_shared<DataElement>("two"), 
    std::make_shared<DataElement>("three"), 
    std::make_shared<DataElement>("four"), 
    std::make_shared<DataElement>("five"), 
    std::make_shared<DataElement>("six"), 
    std::make_shared<DataElement>("seven"), 
    std::make_shared<DataElement>("eight"), 
    }; 
    using iterator_type = std::ostream_iterator<char>; 
    iterator_type out(std::cout); 

    TheGrammar<iterator_type> grammar; 
    return karma::generate(out, grammar, vec); 
} 

Я хотел бы понять несколько вещей:

  1. Почему мне не нужно использовать karma::attr_cast где-нибудь? Мое правило start является вектором std::shared_ptr, тогда как правило elt работает с фактической ссылкой на объект const. Я изначально попробовал attr_cast, но не получил нигде, и вроде бы попробовал эту версию только на редкость на всякий случай, когда это сработало, и это сработало ...
  2. Почему он все еще компилируется, если я вообще комментирую свой обычай transform_attribute? Есть ли по умолчанию std::shared_ptr<T> ->T& transform_attribute? Я не мог найти много, но, может быть, я не смотрю в нужное место?
  3. Если я прокомментирую свой обычай transform_attribute, как уже упоминалось выше, код все еще скомпилирован, но во время выполнения явно наблюдается некоторая поврежденность памяти. karma::string сгенерируйте мусор. В некотором смысле, я могу понять, что что-то смешное должно происходить, так как я даже не говорю о карме, как добраться от моего shared_ptr к объектам. Является ли тот факт, что он компилирует фактическую ошибку/ошибку?

Большое спасибо за ваше время и помощь!

+0

повторно. Вручая попытку attr_cast, вы, возможно, столкнулись с интересной ошибкой, которая существовала (по крайней мере, в части Qi Spirit). Вы можете попытаться добавить 'qi :: copy()' или 'boost :: proto :: deep_copy()' вокруг подвыражения парсера внутри attr_cast – sehe

+0

FWIW Вот где я нашел эту ошибку с 'attr_cast': http://stackoverflow.com/questions/19707254/syntax-tree-empty-nodes-issue-with-spirit-qi-minic-example/19715064#comment31448465_19715064 – sehe

ответ

1
  1. каждое правило имеет неявный attr_cast для объявленного типа атрибута
  2. Somehwere по пути правила совместимости типа духа идти наперекосяк. Все, что я видел, это связано с тем, что тип строки является контейнером. Где-то по пути он «копировать-конструктов» в станд :: строку, которая, как представляется, имеют длину 97332352. Unsurprisingly, что само по себе не так и происходит, чтобы вызвать UB, потому что диапазоны, которые в конечном итоге передается memset перекрытия:

    Source and destination overlap in memcpy(0x60c1040, 0x5cd2c90, 97332352) 
        at 0x4C30573: [email protected]@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
        by 0x401B26: copy (char_traits.h:290) 
        by 0x401B26: _S_copy (basic_string.h:299) 
        by 0x401B26: _S_copy_chars (basic_string.h:342) 
        by 0x401B26: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) [clone .isra.53] (basic_string.tcc:229) 
        by 0x402442: _M_construct_aux<char*> (basic_string.h:195) 
        by 0x402442: _M_construct<char*> (basic_string.h:214) 
        by 0x402442: basic_string (basic_string.h:401) 
        by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:172) 
        by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:184) 
        by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:217) 
        by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:237) 
        by 0x402442: pre (attributes.hpp:23) 
    
  3. Да, это вопрос QoI.

    Проблема часто связана с неявными преобразованиями C++. Типы указателей имеют много неожиданных преобразований. У общих указателей есть своя контекстная конвертация в bool.

Другие ноты:

  1. Ваша адаптация фьюжн казалось ошибочным: val не используется в инкубаторе

    BOOST_FUSION_ADAPT_ADT(DataElement, (std::string &, const std::string &, obj.str(), obj.str() = val)) 
    
  2. Вы делаете много вещей, которые я изучил в избежать.

+1

Большое спасибо! Действительно, моя адаптация была неуклюжей, спасибо за исправление. Это моя первая попытка в духе, не слишком уверенная, что я вижу точку кармы до сих пор, я думаю, что обратное (то есть синтаксический анализ через ци) имеет гораздо больший смысл, но я редко (никогда!) Не должен разбирать пользовательские материалы, поэтому Я решил пропустить генератор ... – rectummelancolique

+0

Я не использую Карму много. Большинство генераторов становятся интересными только при наличии состояния (довольно-печатание/форматирование). Я использую Qi *** ***. Я не знаю, на какой планете вы живете, когда вам не нужно разбирать текст :) – sehe