【问题标题】:Ambiguous operator overload for std::optional?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()等

标签: c++ gcc operator-overloading optional c++17


【解决方案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&amp;)是 Test 的精确匹配,而不是派生到基础的转换。

但是,虽然我们可以更喜欢 #2#3 而不是 #1,但没有理由更喜欢 #2#3 中的一个 - 每个参数在一个参数中都有更好的转换顺序,而更差第二个转换顺序。

因此,它是模棱两可的。请注意#2#3 都是格式正确的运算符,因为您确实可以将intTest 进行比较。为了消除它们的歧义,您必须另外添加一个U 不继承自optional&lt;T&gt; 的约束,这是...一个非常具体的约束。


您可以通过将一个或另一个 Test 转换为 optional&lt;int&gt; 或简单地提供一个 optional==(Test, Test) 来解决此问题。

【讨论】:

  • 最后我添加了optional==(Test, Test),但从库的角度来看,是否应该更喜欢从 std::optional 派生的类而不是这些重载的值?
  • 我认为问题(见问题中的编辑)不是为什么这些重载是模棱两可的,而是为什么委员会没有选择一组不同的重载(与某些 enable_if 相同?)不会模棱两可。
  • @MarcGlisse 一组额外的重载特别用于Uoptional&lt;T&gt;继承的情况?
  • 我没有说这是个好主意,但这就是我对问题的解释。
  • @Barry 是的,对于U 继承自optional&lt;T&gt; 或可转换为optional&lt;T&gt; 的情况,有一组额外的重载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
  • 2010-12-10
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 2019-09-12
相关资源
最近更新 更多