Boost logo

Boost :

Subject: Re: [boost] [uuid] Interface
From: Vladimir.Batov_at_[hidden]
Date: 2008-12-18 16:15:51

>> Great in theory, but I think it'll break
>> lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a"), since the
>> lexical_cast wants to default-construct the target type into which it
>> will read.

Yes, the default lexical_cast behavior requires the default constructor.
Having said that I've been routinely specializing lexical_cast to optimize
away the overhead. Something like

namespace boost
    template<> inline std::string lexical_cast<std::string> (std::string
const& v) { return v; }
    template<> inline std::string lexical_cast<std::string> (char const*
const& v) { return v; }
    template<> inline std::string lexical_cast<std::string> (bool const&
v) { return v ? "yes" : "no"; }

If we do that for boost::uuid, then the user gets the familair interface
and we have our class clean and minimal. Having said that I am honestly
unsure about

        uuid id = lexical_cast<uuid>(str);

as it seems already covered by

        template<typename InputIterator> uuid(InputIterator,

I certainly want the explicitness of "string str =
lexical_cast<string>(id);" though. Still, keeping the bidirectional nature
of lexical_cast is probably important for the user. Therefore, I'd
*probably* have

namespace boost
    template<> inline boost::uuid lexical_cast<std::string> (std::string
const& v)
        return boost::uuid(v.begin(), str.end());

>> template <typename ByteInputIterator>
>> uuid(ByteInputIterator begin, ByteInputIterator end);

Can we take it one step further and replace it with a more generic:

template<class ForwardReadableRange>
uuid(ForwardReadableRange const& range)
        typedef typename boost::range_iterator< ForwardReadableRange
>::type Iterator;

        Iterator begin = boost::begin(range);
        Iterator end = boost::begin(end);

        ... the rest is the same.

That way

        uuid id(string)

is supported without the need for an explicit "uuid::uuid(string const&)"
constructor as other containers as well.

>> > // valid expression
>> > // generator() - result type must be convertible to a uuid
>> > template <typename Generator>
>> > explicit uuid(Generator & generator);

I feel that the "generator() - result type must be convertible to a uuid"
requirement is somewhat excessive. Given the rest of the code it results
in a generator having to know and even be able to create boost::uuid. That
seems like an unnecessary coupling. I think generators should know
*nothing* about uuid and certainly *not* create those. Instead, the
generators should provide the necessary *ingredients* but it'd be uuid
(well, its uuid(generator) constructor) actually creating an uuid
instance. That might be as straghtforward as

template<class Generator>
uuid(Generator const& gen)
        std::pair<Iterator, Iterator> range = gen();
        ... something that uuid(begin, end) or uuid(range) does.

That way, the requirements for a generator are looser as all it needs is
to provide a range. More so, the design maintains the locality of uuid
creation and destruction -- those are created and destructed in the
conventional way, i.e. by the uuid constructor and destructor (rather than
created by a generator but destroyed by the uuid::~uuid()).

As Scott noted

        template<class Generator>
        uuid(Generator const& gen)

constructor is somewhat redundant. However, I'd personally like to keep
it as it communicates to the user one of the main ways of creating a uuid.

>> bool is_nil() const;
>> operator unspecified_bool_type() const; // return !is_nil();

It's a minor point but I'd ask whay we need both? The reason I greatly
favor "bool" converter is that it is idiomatic and does *not* introduce a
new vocabulary. That is important from the usability point of view as any
new vocabulary is obviously only usable *after* one learnt it. Why ask the
user to learn something (like "is_nil") if he can get by without?


Boost list run by bdawes at, gregod at, cpdaniel at, john at