无效的默认值基本上是您设计中的变体。该对象在创建时无效。你应该在合理的时候避免这种情况。绝不应该“不惜一切代价”避免它。
有些问题需要您从变体状态开始。在这种情况下,您必须在心理上推理该无效值。如果您避免命名它,那么您正在积极地降低您的代码的表现力。考虑一下您与以后必须维护代码的人之间的沟通。
顺风处理它很烦人。您从一个变体状态开始,但是当它相关时,您希望它不再是变体。我更喜欢的策略是允许用户忽略变体状态并在我犯错时抛出。
namespace FooType {
enum EnumValue {
INVALID = 0
,valid
};
}
struct Foo {
Foo() : val(FooType::INVALID) {}
FooType::EnumValue get() const {
if (val == FooType::INVALID)
throw std::logic_error("variant Foo state");
return val;
}
FooType::EnumValue val;
};
这使您的用户不必为您的差异进行推理,这是值得为之奋斗的。
如果您无法摆脱这种情况,我通常更愿意降级为安全和不安全的接口。
struct Foo {
Foo() : val(FooType::INVALID) {}
bool get(FooType::EnumValue& val_) const {
if (val == FooType::INVALID)
return false;
val_ = val;
return true;
}
FooType::EnumValue get() const {
FooType::EnumValue val_;
if (!get(val_))
throw std::logic_error("variant Foo state");
return val_;
}
FooType::EnumValue get_or_default(FooType::EnumValue def) const {
FooType::EnumValue val_;
if (!get(val_))
return def;
return val_;
}
FooType::EnumValue val;
};
这些类型的接口适用于可能需要空值的数据库之类的东西。