我有一组看起来像这样的类型:
struct MyFlag
{
SomeId source_id; // INVALID_ID by default
SomeData data; // regular type
friend bool operator==( const MyFlag& a, const MyFlag& b ) { return a.source_id == b.source_id; }
friend bool operator<( const MyFlag& a, const MyFlag& b ) { return a.source_id < b.source_id; }
friend bool operator!=( const MyFlag& a, const MyFlag& b ) { return !(a == b); }
friend bool operator==( const SomeId& a, const MyFlag& b ) { return a == b.source_id; }
friend bool operator<( const SomeId& a, const MyFlag& b ) { return a < b.source_id; }
};
MyFlag flag_a { id, data_A };
MyFlag flag_b { id, data_B };
assert( flag_a == flag_b );
assert( flag_a.data != flag_b.data );
assert( flag_a == id );
assert( flag_b == id );
MyFlag flag = flag_b;
assert( flag == flag_a );
assert( flag == id );
assert( flag.data != flag_a.data );
const MyFlag flag_x ={ id_x, data_A };
flag = flag_X;
assert( flag != flag_a );
assert( flag.data == flag_a.data );
也就是说,在比较中仅考虑对象状态的特定部分:在此示例中,将使用其ID将任何MyFlag对象与其他对象进行比较,但不使用它们包含的其余数据进行比较。
我认为它与肖恩·帕特伦(Sean Parent)对“值类型”的定义相符,但我也认为这是一种奇怪或不熟悉的方法(但对我而言非常有用)。
所以我的问题是:这个...概念有一个概念名称吗?
这种类型有什么用?我在“黑板”事件系统中使用了这种类型,它基本上是一种具有至少常规类型的任何值的集合。
但是,即使已经找到(通过比较),该黑板也会系统地覆盖其中插入(插入)的值。这样,我使用比较运算符作为标识符来覆盖黑板中某个值的完整状态。
我不知道这是不是众所周知的模式或想法,或者从长远来看是否有问题。到目前为止,它非常有用。它也感觉有些“太聪明”,但是我缺乏这种模式的经验来确认这一点。可能是我在滥用比较运算符,但感觉这些类型的语义在我的使用中是正确的。
如有必要,我可以提供我的用法的详细示例。
最佳答案
MyFlag
不是EqualityComparable
,因为==
对于具有不同值的对象返回true。 §3.3中EqualityComparable
的定义包括axiom { a == b <=> eq(a, b); }
。
非正式地,eq
旨在表示我们认为是对象值的相等性,而与该对象类型的==
的存在无关。这与表示形式相等性严格不是同一回事,因为(a)不同的表示形式可以被视为相等(例如-0.0 == 0.0
),并且(b)表示形式中可以存在无关紧要的状态(通俗地称为“填充”)。
对于MyFlag
,我几乎可以肯定的是,在某些情况下data
在MyFlag
的值中被认为是重要的(在OP本身中出现了几次)。形式上,我可以在cmp
上定义一个运算符MyFlag
:
bool cmp(const MyFlag& a, const MyFlag& b) {
return a == b && a.data == b.data;
}
与相应的
operator ==
相比,这显然提供了更强的相等性解释。考虑
std::copy
的实现:template <typename In, typename Out>
Out copy_(In first, In last, Out out, std::false_type) {
while(first != last) {
*out++ = *first++;
}
}
template <typename In, typename Out>
Out copy_(In first, In last, Out out, std::true_type) {
while(first != last) {
*out = *first;
*out.data = SomeData();
++first;
++out;
}
}
template <typename In, typename Out>
Out copy(In first, In last, Out out) {
copy_(first, last, out, std::is_same<
Myflag,
typename std::iterator_traits<In>::value_type>());
}
您会认为这是
copy
的有效实现,还是会说它正在破坏数据?根据Myflag
的operator ==
,它保持相等。相反,
Myflag
是否定义为:class MyFlag
{
SomeData trash_bits;
public:
SomeId source_id; // INVALID_ID by default
friend bool operator==( const MyFlag& a, const MyFlag& b ) { return a.source_id == b.source_id; }
friend bool operator<( const MyFlag& a, const MyFlag& b ) { return a.source_id < b.source_id; }
friend bool operator!=( const MyFlag& a, const MyFlag& b ) { return !(a == b); }
friend bool operator==( const SomeId& a, const MyFlag& b ) { return a == b.source_id; }
friend bool operator<( const SomeId& a, const MyFlag& b ) { return a < b.source_id; }
};
您可能会提出一个令人信服的论点,因为
trash_bits
从未被观察到,因此不属于MyFlag
值。然后,我同意MyFlag
是Regular
。