
I think the terminology "valid object" is misleading here. A NULL pointer is valid. An uninitialized pointer is... marginally valid. I don't think anyone is suggesting that uuid() should produce an object that can only be assigned to or destroyed.
I most certainly agree that "valid/invalid" is far from ideal. It immediately opens up a possibility for a hair-splitting discussion about validity of uuid::nil(). From technical point of view uuid::nil() is certainly valid. For all other *practical* purposes it is not as uuid::nil() and NULL are created to be different from and in contrast with all the other "good" (valid?) objects. In my code I simply use something like foo::bad() to identify such instances.
The latter is not how the language interprets the default constructor.
I can't imagine what you mean by that.
My point was that the default constructor is part of the constructors family and, therefore, should behave consistently with the other constructors. And by "consistently" I mean predictably, across many classes. And overwhelmingly that is the initialization of "good" objects. Therefore, I'd expect the conceptual behavior of a custom Foo::Foo() to be similar to Foo(type =def_value) (which happens to be the default constructor as well) and auto-generated Foo() and all other constructors. Similarly to Stroustrup's "The C++ Progr. Lang." 10.2.3: class Date { ... Date(); // default Date: today }; Having said that I realize that approach causes a bit of a technical headache to the class developer as, say, lexical_cast does not work out of the box. Still, I'd go for it if a headache for one (the developer) makes life of many (users) easier.
Second, even if I cannot use operator[], so what? std::fstream has no default constructor. std::list has no operator[], std::vector has no push_front(). That did not stop anyone from using those classes. What the lack of those "features"
Do you really mean to imply that push_front, operator[], et. al. are not legitimate features?
Well, I most certainly did not mean to unconditionally imply that op[] et al are not legitimate. For some classes some functionality is not legitimate. Like std::list does have op[] for a reason. I think Scott's argument was that without the def. cnstr we woun't be able to use op[] with std::map<string, uuid>. My argument was that some things have some features and some others don't. That is there (or not there) for a purpose. If we, say, banish foo::foo() then is for a reason. Consequently, the functionality dependent on that foo::foo() will not be available for that same reason -- 'foo' should not be created with the def. cnstr. Did I manage to explain it better this time? Best, V.