|
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,
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?
Thanks,
Vladimir.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk