#include #include #include #include #include #include namespace proto = boost::proto; struct map_ {}; boost::proto::terminal::type map = {}; typedef std::map string_map; // Recursive function used to fill the map template< class Expr > void fill_map( Expr const & expr, string_map & subs ) { using boost::proto::value; // read a value from a terminal using boost::proto::child_c; // get the Nth child of a non-terminal subs[ value(child_c<1>( expr )) ] = value(child_c<2>(expr)); fill_map( child_c<0>(expr), subs ); } // The 'map' terminal ends the recursion void fill_map( boost::proto::terminal::type const &, string_map & ) {} // The old format API that accepts a map of string substitutions std::string format( std::string fmt, string_map & subs ) { namespace xp = boost::xpressive; using namespace xp; sregex const rx = '{' >> (s1= +_w) >> '}'; // like "{(\\w+)}" return regex_replace(fmt, rx, xp::ref(subs)[s1]); } // The new format API that forwards to the old one /* Replaced by Validation 1. template< class Expr > std::string format( std::string fmt, Expr const & expr ) { string_map subs; fill_map( expr, subs ); return format( fmt, subs ); } */ // Define the grammar of map expressions struct MapGrammar : proto::or_< // A map expression is a map terminal, or proto::terminal // ... a ternary function non-terminal where the child nodes are , proto::function< // ... a map expression, MapGrammar // ... a narrow string terminal, and , proto::terminal // ... another narrow string terminal. , proto::terminal > > {}; // Validation version 1. /* replaced by Validation 2. template< class Expr > std::string format( std::string fmt, Expr const & expr ) { // Comment removed. static_assert( proto::matches::value , "The map expression passed to format does not match MapGrammar"); string_map subs; fill_map( expr, subs ); return format( fmt, subs ); } */ template< class Expr > std::string format_impl( std::string fmt, Expr const & expr, boost::mpl::true_ ) { string_map subs; fill_map( expr, subs ); return format( fmt, subs ); } template< class Expr > std::string format_impl( std::string fmt, Expr const & expr, boost::mpl::false_ ) { return std::string(); // never called for valid imput } // Validation 2. template< class Expr > std::string format( std::string fmt, Expr const & expr ) { /* READ THIS IF YOUR COMPILE BREAKS ON THE FOLLOWING LINE * * You have passed to format an invalid map expression. * They should be of the form: * map("this", "that")("here", "there") */ static_assert( proto::matches::value , "The map expression passed to format does not match MapGrammar"); /* Dispatch to the real implementation or a stub depending on whether our parameters are valid or not. */ return format_impl( fmt, expr, proto::matches() ); } int main() { std::cout << format("The home directory of {user} is {home}\n" , map("user", "eric") ("home", "/home/eric") ); } /* error message: map_example2_cxx0x_clang31_libc++: boost_1_50_0/boost/xpressive/traits/cpp_regex_traits.hpp:273: void boost::xpressive::detail::cpp_regex_traits_base::imbue(const std::locale &) [Char = char, SizeOfChar = 1]: Assertion `0 == (this->masks_[i] & non_std_ctype_masks)' failed. Aborted */