2016-06-20 7 views
3

나는 다음과 같은 코드 조각을 가지고 있습니다. (나는 의미론적인 행동을 reuse parsed variable with 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

재 ADT 적응하지 않습니다. 수동으로 attr_cast를 시도하면 (적어도 Spirit의 Qi 부분에서는) 존재하는 흥미로운 버그가 발생할 수 있습니다. attr_cast 내부의 파서 서브 표현식 주위에'qi :: copy()'또는'boost :: proto :: deep_copy()'를 추가하려고 할 수 있습니다. – 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. 각 규칙은 Somehwere 성령의 유형 호환성 규칙이 훙 분하다 길을 따라 선언 된 속성 유형
  2. 에 대한 암시 attr_cast 있습니다. 내가 본 모든 것은 문자열 유형이 컨테이너라는 사실과 관련이있다. 어딘가에 길을 "복사 구조"길이 97332352.은 당연히 그 자체가 잘못이 보이며 결국 범위가 memset 중복에 전달되고 있기 때문에 UB를 트리거 일어나는 표준 : : 문자열 함께 :

    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. 당신은 I가 배운 많은 일을하고있는 세터에서 사용되지 않았다 기피.

+1

고마워요! 실제로 나의 적응은 고약한 데, 고쳐 주셔서 감사합니다. 이것은 정신에 대한 나의 첫 번째 시도이다. 나는 지금까지 업보의 요점을 보았지만, 역 (즉, 제나라를 통해 파싱)은 훨씬 더 의미가 있다고 생각하지만, 드물게 (결코!) 사용자 정의 내용을 파싱해야한다. 나는 발전기를 타고 가기로 결심했다. ... – rectummelancolique

+0

나는 운명을 많이 사용하지 않는다. 대부분의 생성자는 상태 저장 (pretty-printing/formatting)이 필요한 경우에만 흥미로워집니다. Qi *** *** 많이 사용 ***. 텍스트를 파싱 할 필요가 없을 때 나는 어떤 행성에 살고 있는지 모른다. :) – sehe