我有一组看起来像这样的类型:

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,我几乎可以肯定的是,在某些情况下dataMyFlag的值中被认为是重要的(在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的有效实现,还是会说它正在破坏数据?根据Myflagoperator ==,它保持相等。

相反,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值。然后,我同意MyFlagRegular

10-07 13:34