metaparse icon indicating copy to clipboard operation
metaparse copied to clipboard

Proposal for value-based Interface in Boost.Metaparse

Open denzor200 opened this issue 3 months ago • 2 comments

Motivation

Boost.Metaparse is a powerful library for compile-time parsing, but its interface remains largely centered around template metafunctions in the classic typename ... style. While the library has already taken a step toward value-based with BOOST_METAPARSE_STRING_VALUE—this improvement is only partial. In 2025, developers should not be forced to write verbose and archaic constructs like:

typedef
  foldl_reject_incomplete1<
    one_of<
      always_c<'.', r_any_char>,
      transform<one_char_except_c<'.', '(', ')'>, r_char_lit>
    >,
    r_epsilon,
    r_append
  >
  non_bracket_expr;

Such syntax is not only cumbersome and hard to read, but it also stands in stark contrast to modern C++ idioms. The existing value-based support for strings demonstrates the library's potential to evolve, but stopping halfway leaves the interface inconsistent and underutilized.

I propose to complete this evolution by introducing a comprehensive, value-based C++11 interface for the entire library. This will align Boost.Metaparse with contemporary C++ practices, making it more accessible, expressive, and maintainable.

Proposed Solution

Extend the value-based approach consistently across all metafunctions by introducing lightweight constexpr wrapper functions. Each wrapper will accept value-based arguments (types as template parameters, callable objects, or already wrapped values) and return an instance of the corresponding Boost.Metaparse metafunction. For example:

template<typename Left, typename Middle, typename Right>
constexpr auto middle_of(Left, Middle, Right) -> 
    boost::metaparse::middle_of<Left, Middle, Right>
{
    return {};
}

We have to negotiate the way how to ensure full backward compatibility and a clear distinction from the classic metafunction-based interface. As a temporary solution i've put all these wrappers into boost::metaparse::cxx11.

Benefits

  1. Consistency – If BOOST_METAPARSE_STRING_VALUE enables value-based strings, why should the rest of the library remain type-based? A uniform value-based interface eliminates cognitive dissonance and simplifies learning.
  2. Modern readability – Complex parser definitions become clean, linear, and visually similar to runtime parsing code—lowering the barrier for new users.
  3. Seamless integration with modern C++ – The wrappers leverage constexpr, auto, and lambda expressions, fitting naturally into C++11 and beyond.
  4. Zero-cost abstraction – The wrappers are trivial, header-only, and impose no compile-time or runtime overhead.
  5. Progressive evolution – This change complements rather than replaces the existing interface, allowing gradual adoption.

Example Transformation

With the proposed wrappers, the regexp example from the repository transforms into a much clearer and more maintainable form:

#include "boost_metaparse_cxx11/wrappers.hpp"
#include <iostream>
#include <boost/xpressive/xpressive.hpp>

using boost::metaparse::cxx11::foldl_reject_incomplete;
using boost::metaparse::cxx11::foldl_reject_incomplete1;
using boost::metaparse::cxx11::lit_c;
using boost::metaparse::cxx11::transform;
using boost::metaparse::cxx11::build_parser;
using boost::metaparse::cxx11::one_of;
using boost::metaparse::cxx11::always_c;
using boost::metaparse::cxx11::middle_of;
using boost::metaparse::cxx11::one_char_except_c;
using boost::metaparse::cxx11::entire_input;

using boost::xpressive::sregex;
using boost::xpressive::as_xpr;

void test_string(const std::string& s)
{
  /*
  * Results of parsing
  */

  using boost::xpressive::sregex;
  using boost::xpressive::as_xpr;

  constexpr auto r_any_char = []() {
    return boost::xpressive::_;
  };

  constexpr auto r_char_lit = [](char C) {
    return as_xpr(C);
  };

  constexpr auto r_append = [](const sregex& lhs, const sregex& rhs) -> sregex {
    return lhs >> rhs;
  };

  constexpr auto r_epsilon = []{
    return as_xpr("");
  };

  using boost::xpressive::regex_match;
  using boost::xpressive::smatch;
  using std::cout;
  using std::endl;

  /*
  * The grammar
  *
  * regexp ::= (bracket_expr | non_bracket_expr)*
  * non_bracket_expr ::= '.' | char_lit
  * bracket_expr ::= '(' regexp ')'
  * char_lit ::= any character except: . ( )
  */

  constexpr auto non_bracket_expr = foldl_reject_incomplete1(
    one_of(
      always_c<'.'>(r_any_char),
      transform(
        one_char_except_c<'.', '(', ')'>(),
        r_char_lit
      )
    ),
    r_epsilon,
    r_append
  );

  constexpr auto bracket_expr = middle_of(
    lit_c<'('>(),
    non_bracket_expr,
    lit_c<')'>()
  );

  constexpr auto regexp = foldl_reject_incomplete(
    one_of(
      bracket_expr,
      non_bracket_expr
    ),
    r_epsilon,
    r_append
  );

  constexpr auto regexp_parser =
    build_parser(entire_input(regexp));

  const sregex re = regexp_parser(BOOST_METAPARSE_STRING_VALUE(".(bc)"));

  smatch w;

  cout << s << (regex_match(s, w, re) ? " matches " : " doesn't match ")
    << ".(bc)" << endl;
}

int main()
{
  test_string("abc");
  test_string("aba");

  return 0;
}

Working prototypes are available:

  • C++11 prototype: https://godbolt.org/z/8PP1Y9sn3
  • C++20 prototype: https://godbolt.org/z/EGP7xsaG7

The wrapper implementation (sufficient for the regexp example) can be reviewed here:
https://github.com/denzor200/boost_metaparse_cxx11/blob/main/wrappers.hpp

Implementation Outline

The change is non-breaking and can be introduced incrementally. It requires only the addition of header files containing wrapper functions for each metafunction—building naturally on the foundation laid by BOOST_METAPARSE_STRING_VALUE.

Conclusion

Boost.Metaparse has already begun moving toward a value-based interface. Let’s finish that journey. By extending this approach library-wide, we can modernize Boost.Metaparse, enhance its usability, and ensure it remains a first-choice tool for compile-time parsing in modern C++. I am eager to contribute a pull request if the idea is accepted.

Thank you for your consideration.

denzor200 avatar Dec 12 '25 00:12 denzor200