
"Declaration without definition" is extern.
Re-read Stroustrup's 4.9 and indeed I mis-interpreted "Any declaration that specifies a value is a definition". After close reading I see that char ch; int i; which I referred to as "declarations without definition" are indeed definitions. Should have been using something like "definition without value/initialization".
I think you mean uninitialized, which *is* allowed in classes, if they're aggregates. I've already uploaded a version that does exactly that.
Yes, I meant uninitialized. And I indeed remember that "classes, if they're aggregates" are allowed uninitialized. I am not a lawer though and I was not writing a specification. So, I was hoping the context was understood -- I was talking about mainstream "normal" classes and not those clearly dragged in due to backward compatibility with C. Consequently, I omitted that fringe (in my view and usage pattern) case.
Therefore, IMHO making them *look* like they behave similarly to built-ins sends/enforces the wrong message/impression.
So why not make them behave like them? I've always heard "do as the ints do" as the guideline for value types.
Because I do not believe we can. The distinctive difference between built-ins and classes (well, classes which are not aggregates. Pls let me skip mentioning that every time I say "class") is that built-ins (and class aggregates) allow "definition without initialization" and classes do not (well, classes which are not aggregates. Pls let me not mention that every time I say "class"). I.e. the two below do different things and carry different overhead: int i; // build-in uninitialized. Kind of a place-holder Foo foo; // class. default initialized stream >> i; stream >> foo; As for "why not make them behave like them", I had that crazy idea too dreaming why could not C++ introduce something like 'noninvariant' -- "defined uninitialized" for classes. Then, int i; // non-initialized place-holder Foo::noninvariant foo; // non-initialized place-holder stream >> i; stream >> foo; Then, I'd think we'd reconcile built-ins and classes once and for all. That functionality is needed as we've been using some sort of it with placement new(). However, that might be too far-fetched (and maybe troublesome) a dream. In the end we seem to get-by as it is. We call Foo foo; stream >> foo; if Foo::Foo() is acceptable or, say, Foo foo = Foo::null(); stream >> foo; if for whatever reason Foo::Foo() is not good/available. In uuid context it might be boost::uuid uuid(uuid::nil); stream >> uuid; That seems as close as we can get to mimic built-ins behavior.
If you allow a constructor for making the nil value (obviously I would like the default constructor, but a function pointer so you could do uuid(uuids::nil) would be fine in your way), then there's no need for uuid::nil() to have a loop, since it can value-initialize the member array (which is an aggregate) letting the compiler use the most efficient zeroing method it has.
I do not insist on m_uuid(uuid::nil()) initialization. I insist (well, if I can insist on anything) on making a uuid::nil explicit. Your suggestion looks good to me. Best, V.