std :: optional的模棱两可的运算符重载?
Posted
技术标签:
【中文标题】std :: optional的模棱两可的运算符重载?【英文标题】:Ambiguous operator overload for std::optional? 【发布时间】:2017-03-21 13:06:02 【问题描述】:考虑this 代码。
struct Test : public std::optional<int> ;
Test o1, o2;
o1 == o2;
对于最后一行gcc-7.0.1
抱怨error: ambiguous overload
指向两个重载,用于比较一个可选值和一个值。但是它不应该只是选择带有两个可选的重载并成功编译代码吗?
编辑 值比较的重载不应该有“守卫”不允许它们实例化从 std::optional 继承的类型吗?
【问题讨论】:
一个更好的问题是你为什么要从optional
继承?
@Nicol Bolas 好吧,为了给它增加一些额外的语义负载 ։) 建立一个私有成员可能是另一种选择,但这是一个更糟糕的选择,因为我需要 std::optional
的所有功能提供另外我正在添加更多功能。不想重新定义reset()、emplace()等
【参考方案1】:
将为这个表达式找到三个重载:
// #1, with T=int, U=int
template <class T, class U>
constexpr bool operator==(optional<T> const&, optional<U> const& );
// #2, with T=int, U=Test
template <class T, class U>
constexpr bool operator==(optional<T> const&, U const& );
// #3, with T=int, U=Test
template <class T, class U>
constexpr bool operator==(U const&, optional<T> const& );
#2
和 #3
具有比 #1
更好的转换序列,因为其中一个参数(U const&
)是 Test
的精确匹配,而不是派生到基础的转换。
但是,虽然我们可以更喜欢 #2
和 #3
而不是 #1
,但没有理由更喜欢 #2
或 #3
中的一个 - 每个参数在一个参数中都有更好的转换顺序,而更差第二个转换顺序。
因此,它是模棱两可的。请注意#2
和#3
都是格式正确的运算符,因为您确实可以将int
与Test
进行比较。为了消除它们的歧义,您必须另外添加一个U
不继承自optional<T>
的约束,这是...一个非常具体的约束。
您可以通过将一个或另一个 Test
转换为 optional<int>
或简单地提供一个 optional==(Test, Test)
来解决此问题。
【讨论】:
最后我添加了optional==(Test, Test)
,但从库的角度来看,是否应该更喜欢从 std::optional 派生的类而不是这些重载的值?
我认为问题(见问题中的编辑)不是为什么这些重载是模棱两可的,而是为什么委员会没有选择一组不同的重载(与某些 enable_if 相同?)不会模棱两可。
@MarcGlisse 一组额外的重载特别用于U
从optional<T>
继承的情况?
我没有说这是个好主意,但这就是我对问题的解释。
@Barry 是的,对于U
继承自optional<T>
或可转换为optional<T>
的情况,有一组额外的重载。以上是关于std :: optional的模棱两可的运算符重载?的主要内容,如果未能解决你的问题,请参考以下文章
在哪些情况下 std::optional operator == 会导致未定义的行为?
为啥 std::optional 不允许“移动构造和仅复制分配”类型的移动分配?