为什么std::variant不能与其中一个备选类型进行等于比较?

14
例如,将std::variant<T1, T2>T1T2进行等值比较应该非常有帮助。目前我们只能与相同的变体类型进行比较。

4
我认为C++20刚刚通过“母舰提案”将其添加到了草案中。具体内容请查看链接:https://brevzin.github.io/cpp_proposals/118x_spaceship/p1614r0.html#was-ill-formed-now-well-formed - Guillaume Racicot
1
@GuillaumeRacicot 在同一个链接中,我认为它是在说int将被隐式转换为std::variant<int, std::string>以满足比较函数签名。对于int来说,这可能是微不足道的。但对于字符串来说,这可能意味着复制。 - Cruz Jean
C++17中的比较操作符不应该也能工作吗?operator==是一个独立函数。variant有一个非显式转换构造函数,所以variant<T1, T2>() == T1()应该将T1转换为variant<T1, T2>,然后找到独立的operator==。实际上,在检查后我发现它并不能正常工作。这是为什么呢? - Kilian
实际上以下代码是有效的: struct X { template<class T> X(T&&) {} }; bool operator==(X const&, X const&); X x(10); bool b = x==10;因此,它似乎与operator==是一个模板有关。 - Kilian
3个回答

11

变量可能有多个相同类型的副本。例如:std::variant<int, int>

如果一个 std::variant 实例持有相同的变体替代项并且这些替代项的值相等,则它与另一个实例相等。

因此,index() 为 0 的 std::variant<int, int>index() 为 1 的 std::variant<int, int> 不相等,尽管活动的变体替代项是相同类型和相同值。

由于这个原因,标准没有实现通用的“与 T 比较”的功能。但是,您可以自由设计自己的比较运算符重载,使用其他辅助工具(例如 std::holds_alternativestd::get<T>)在 <variant> 头文件中。


3
当比较一个 intstd::variant<int, int> 时,它可以将 活动 成员与该 int 进行比较。 - Maxim Egorushkin
@MaximEgorushkin,你可能希望它是那样的,但这不是标准决定的。 - Cruz Jean
有点离题,但标准库在被集成到标准中时就已经过时了,然后只是在那里腐烂,因为标准库更新几乎不存在。在我看来,标准委员会最好专注于模块、构建和打包系统,这样人们可以随意选择和匹配库。 - Maxim Egorushkin
1
@MaximEgorushkin boost::variant 也不支持与其中一种备选类型的相等比较。 - Barry
1
@MaximEgorushkin 因为 variant<a,b,c> 总是 具有 b 作为替代 1,如果 var1 的替代品不是 var2 的替代品,它们永远不会相等。 如果你走了“好吧,我确定他们在说 variant<int, int, double> 时是指 variant<int, double>”,那么就像 JavaScript 中的 "1"==1 那样荒谬。 如果您想进一步了解,请查阅类型理论中的“和类型”。 - Yakk - Adam Nevraumont
显示剩余10条评论

6
这是标准委员会的任意决定。
好吧,不完全是任意的。关键在于你有一个严格比较的等级刻度,具有以下几点:
- 最严格:只有变量可以相互匹配,并且它们需要在备选项序列(即类型)、实际备选项(真正的索引,因为您可以有多个相同类型的备选项)和值方面匹配。 - 较不严格:变体备选项的类型和值都相等,但备选项序列和序列中的索引不相等(因此,在相同类型的两个不同备选项中相同值将被视为相等)。 - 最宽松:活动备选项的值相等,如果相关,则隐式转换其中一个元素。
这些都是有效的选择。C++委员会基于各种外部标准做出了决定。尝试查找std::variant提案,可能会说明这些标准是什么。
(*)- 实际上是一个格子。

5

我无法回答问题的“为什么”部分,但是既然您认为能够比较std::variant<T1, T2>T1T2将会很有用,那么也许这可以帮助您:

template<typename T, class... Types>
inline bool operator==(const T& t, const std::variant<Types...>& v) {
    const T* c = std::get_if<T>(&v);

    return c && *c == t; // true if v contains a T that compares equal to t
}

template<typename T, class... Types>
inline bool operator==(const std::variant<Types...>& v, const T& t) {
    return t == v;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接