#include #include #include #include #include #include #include #include namespace x3 = boost::spirit::x3; // just an `attr` with added type checker template struct checked_attr_parser : x3::attr_parser { using base_t = x3::attr_parser; checked_attr_parser(Value const& value) : base_t(value) {} checked_attr_parser(Value&& value) : base_t(std::move(value)) {} template bool parse(Iterator& first, Iterator const& last , Context const& ctx, RuleContext& rctx, Attribute& attr_) const { static_assert(boost::is_same::value, "attribute type check failed"); return base_t::parse(first, last, ctx, rctx, attr_); } }; template static inline checked_attr_parser, Expected> checked_attr(Value&& value) { return { std::forward(value) }; } // instantiate our type checker // (checks attribute value just to be sure we are ok) template static void test_expr(Value const& v, Expr&& expr) { char const* it = ""; Value r; BOOST_TEST((x3::parse(it, it, std::forward(expr), r))); BOOST_TEST((r == v)); } template static void gen_sequence(Attribute const& attribute, Expr&& expr) { test_expr(attribute, expr); test_expr(attribute, expr >> x3::eps); } template static void gen_sequence(Attribute const& attribute, Expr&& expr, Value const& v, Tail const&... tail) { gen_sequence(attribute, expr >> checked_attr(v), tail...); gen_sequence(attribute, expr >> x3::eps >> checked_attr(v), tail...); gen_sequence(attribute, expr >> (x3::eps >> checked_attr(v)), tail...); } template static void gen_sequence_tests(Attribute const& attribute, Value const& v, Tail const&... tail) { gen_sequence(attribute, checked_attr(v), tail...); gen_sequence(attribute, x3::eps >> checked_attr(v), tail...); } template static void gen_single_item_tests(Value const& v) { Expected attribute(v); gen_sequence(attribute, checked_attr(v)); gen_sequence(attribute, x3::eps >> checked_attr(v)); } template static void gen_single_item_tests(Value const& v, Tail const&... tail) { gen_single_item_tests(v); gen_single_item_tests(tail...); } template static void gen_tests(Values const&... values) { gen_single_item_tests(values...); boost::fusion::vector attribute = boost::fusion::make_vector(values...); gen_sequence_tests(attribute, values...); } template void make_test(Attributes const&... attrs) { // I would like to place all of this in a single call // but it requires tremendous amount of heap to compile gen_tests(attrs...); gen_tests< boost::optional... , boost::fusion::vector... >(attrs..., attrs...); gen_tests< boost::optional>... , boost::fusion::vector>... >(boost::fusion::vector(attrs)..., attrs...); } int main() { make_test(123, "hello"); return boost::report_errors(); }