继承的合成比较运算符产生警告/错误:ISO C++20 考虑使用重载运算符"!="



在下面的代码片段中clang 11.0.1生成一个警告

template <class T>
struct iterator_facade
{
template<class S>
bool operator==(const S &other) const noexcept
{
return static_cast<const T &>(*this).equal_to(other);
}
};
struct iterator : public iterator_facade<iterator>
{
bool equal_to(const iterator &) const noexcept
{
return true;
}
};
bool check(iterator a, iterator b)
{
return a == b;
}

代码:https://godbolt.org/z/65zWEq

source>:21:14: warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'iterator' and 'iterator') to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator]
return a == b;
~ ^  ~
<source>:5:7: note: ambiguity is between a regular call to this operator and a call with the argument order reversed
bool operator==(const S &other) const noexcept
^

上面的代码在Visual c++ (VS 16.8.x)和以前的预览版(VS 16.9.0 preview 2)下可以成功编译。但是,最近发布的VS 16.9.0 preview 3现在会对这个代码片段产生错误:

1>C:MyProjectstesttestsource.cpp(21,16): error C2666: 'foo<bar>::operator ==': 2 overloads have similar conversions
1>C:MyProjectstesttestsource.cpp(5,7): message : could be 'bool iterator_facade<iterator>::operator ==<bar>(const S &) noexcept const' [rewritten expression '!(x == y)']
1>        with
1>        [
1>            S=iterator
1>        ]
1>C:MyProjectstesttestsource.cpp(5,7): message : or 'bool iterator_facade<iterator>::operator ==<iterator>(const S &) noexcept const' [synthesized expression '!(y == x)']
1>        with
1>        [
1>            S=iterator
1>        ]
1>C:MyProjectstesttestsource.cpp(21,16): message : while trying to match the argument list '(iterator, iterator)'

是否看起来没有兼容的方法来为派生类iterator与CRTP类iterator_facade提供合成比较运算符?

问题是我们有这个比较运算符:

template<class T>
struct iterator_facade
{
template <class S>
bool operator==(const S &other) const noexcept;
};

所以当我们尝试比较两个iterator时,我们有这两个候选:

bool operator==(iterator_facade<iterator> const&, iterator const&); // the member candidate
bool operator==(iterator const&, iterator_facade<iterator> const&); // the reversed member candidate

问题是候选成员在第二个参数中是精确匹配的,但在第一对中是派生到基的转换…反转的候选对象在第一个参数中是完全匹配的,但在第二个参数中是派生到基的转换。这意味着没有一个候选人比另一个候选人好,而且两者是模糊的。

现在,由于这个库实际上需要c++ 20开始,所以这有点没有意义。只要让iterator自己实现operator==,这就增加了…没有什么?我也不确定它到底增加了什么。

但是如果你真的想让它工作,你需要提供第二个重载,它接受两个派生的实例。如:

template <class T>
struct iterator_facade
{
friend bool operator==(T const& a, T const& b) noexcept {
return a.equal_to(b);
}
template <sentinel_for<T> S>
bool operator==(S const& other) const noexcept;
};

同构操作符将比异构操作符更好地匹配,因此比较可以很好地编译。

相关内容

  • 没有找到相关文章

最新更新