질문은 맨 아래에 굵게 표시되어 있으며 문제는 끝 부분의 증류 코드 조각으로 요약됩니다.
내 유형 시스템 (유형 시스템이 유형에서 문자열로, 유형에서 문자열로 수행)을 단일 구성 요소 (Lakos에서 정의한대로)로 통합하려고합니다. 내가 사용하고 boost::array
, boost::variant
하고, boost::mpl
이를 달성하기 위해. 내 유형에 대한 파서 및 생성기 규칙을 변형으로 통합하고 싶습니다. 정의되지 않은 유형, int4 (아래 참조) 유형 및 int8 유형이 있습니다. 변형은 variant<undefined, int4,int8>
.
int4 특성 :
struct rbl_int4_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;
boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule_type rule;
rbl_int4_parser_rule_definition()
{
rule.name("rbl int4 rule");
rule = parser_int32_t;
}
};
template<>
struct rbl_type_parser_rule<rbl_int4>
{
typedef rbl_int4_parser_rule_definition string_parser;
};
위의 변형은 정의되지 않은 것으로 시작한 다음 규칙을 초기화합니다. 문제가 발생하여 50 페이지의 오류가 발생했고 마침내 추적 할 수있었습니다. Variant는 operator=
할당 중에 사용 하고 a boost::spirit::qi::int_parser<>
는 다른 사람에게 할당 할 수 없습니다 (operator =).
대조적으로, 정의되지 않은 유형에는 문제가 없습니다.
struct rbl_undefined_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, void()> rule_type;
rule_type rule;
rbl_undefined_parser_rule_definition()
{
rule.name("undefined parse rule");
rule = boost::spirit::qi::eps;
}
};
template<>
struct rbl_type_parser_rule<rbl_undefined>
{
typedef rbl_undefined_parser_rule_definition string_parser;
};
문제의 증류 :
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <boost/cstdint.hpp>
typedef boost::spirit::qi::rule<std::string::iterator,void()> r1;
typedef boost::spirit::qi::rule<std::string::iterator,int()> r2;
typedef boost::variant<r1,r2> v;
int main()
{
/*
problematic
boost::spirit::qi::int_parser<int32_t> t2;
boost::spirit::qi::int_parser<int32_t> t1;
t1 = t2;
*/
//unproblematic
r1 r1_;
r2 r2_;
r1_ = r2_;
v v_;
// THIS is what I need to do.
v_ = r2();
}
구체적인 파서와 규칙 사이에는 의미 론적 차이가 있습니다. 내 뇌는 지금 담배를 피우고 있으므로 실용주의에 대해 생각하지 않을 것입니다. 제 질문은이 문제를 어떻게 해결해야 하는가입니다. 문제를 해결하기위한 세 가지 접근 방식을 생각할 수 있습니다.
1 : 정적 함수 멤버 :
struct rbl_int4_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;
//boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule_type rule;
rbl_int4_parser_rule_definition()
{
static boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule.name("rbl int4 rule");
rule = parser_int32_t;
}
};
접근 방식 1이 스레드 안전 코드를 방지한다고 생각합니까? ?
2 : 정수 파서가 shared_ptr에 래핑됩니다. 타이핑 시스템에 대해 TMP를 사용하는 데는 두 가지 이유가 있습니다. 하나는 효율성이고 두 가지는 구성 요소에 대한 집중화입니다. 포인터를 사용하면 첫 번째 이유가 실패합니다.
세 : operator =는 no-op으로 정의됩니다. Variant lhs
는 할당 전에 기본적으로 생성 되도록 보장 합니다.
편집 : 나는 옵션 3이 가장 합리적이라고 생각합니다 (연산자 = 작동하지 않음). 규칙 컨테이너가 생성되면 변경되지 않으며 유형의 규칙 특성을 오프셋에 강제로 할당 할뿐입니다.
parser_int32_t
상태가 있고 참조가 사용됩니다. 상태 비 저장 또는 복사본이 만들어지면 안전합니다. 의미론에서 나는 사본이 만들어 졌다고 말할 것입니다.