From: Dean M. B. <mik...@gm...> - 2008-10-26 13:48:37
|
Hi Kim, On Sun, Oct 26, 2008 at 9:36 PM, Kim Gräsman <kim...@gm...> wrote: > Hi Dean, > > I'm not John, but his code got me thinking... > It's alright, it's just for discussion anyway. ;-) > On Sun, Oct 26, 2008 at 15:14, Dean Michael Berris > <mik...@gm...> wrote: >> >> On Fri, Oct 24, 2008 at 5:38 AM, John P. Feltz <jf...@ov...> wrote: >>> >>> I implemented this in a similar network client project some time ago: >>> >>> namespace rfc3986 { >>> template < >>> typename ParserInput = std::string, >>> typename Scheme = std::string, >>> typename Authority = std::string, >>> typename Path = std::string, >>> typename Query = std::string, >>> typename Fragment =std::string >>> > class URI { >>> public: >> >> We use traits for these things, and have a simple 'Tag' template argument. > > What's interesting about John's approach is not that std::string is > configurable, but that he can write a specific parser for each part of > the URI, and maybe compose them in the full parse() function. > But that doesn't require you to not use tags either. >>> private: >>> typedef URI< ParserInput, Scheme, Authority, Path, Query, >>> Fragment> Output; >>> >>> friend Output* parse< ParserInput, Output> >>> (std::stack<std::string>& errors, const ParserInput& input); >> >> Why a friend class for the parsing? > > Friend function. Yes, my bad. Either way, I don't think it's necessary. > Presumably because you can easily add new parsers. I > think the main parser works something like this: > > template< class Input, class Output > > Output* parse(const Input& input) > { > return NULL; > } > > > template< > > URI<>* parse(const URI<>::ParserInput& input) > { > URI<>::Scheme_type scheme = parse<URI<>::ParserInput, > URI<>::Scheme_type>(input); > URI<>::Authority_type host = parse<URI<>::ParserInput, > URI<>::Authority_type>(input); > // ... > > return new URI<>(scheme, host, ...); > } > > What I think is interesting about this is that we can let the > authority be represented by a string where we don't care much about > the details (e.g. mailto scheme) or a typed struct where we do (e.g. > http scheme), and just provide a new type + corresponding parser to > make it work. > But that spells bad design because you're going to be specializing template functions instead of specializing classes (which is what should be done anyway IMO): template <class Tag> struct uri_parts; // container of URI parts template <class Tag> struct uri : uri_parts<Tag>; // a URI can be of many types So for instance I need a uri<http::url> to construct an http::request, then the parser of the uri<http::url> would take into consideration everything that needs to be included in a uri<http::url>. Converting from one uri type to another (defined by the actual protocol you intend to use the URI for) should be a conversion function that throws on error. This makes it predictable and simple. > Not sure if I'm reading too many capabilities into John's design, but > I figure this is its main benefit. > Which actually brings in a brittle design relying on free functions and pointers and whatnot. Let's stick with the simple approach of using POD's (or fusion sequences) and class templates for type safety wherever we can, shall we? ;-) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |