为什么std::variant允许多次持有相同类型?

11

5
我猜想historical被用作union的替代品,它也可以容纳相同类型的多个值。在这种情况下,请使用按索引获取。 - Richard Critten
4
适用于通用代码。如果你有两种类型不确定,可以使用 std::variant<T, U>,如果 TU 恰好相同,那没关系。 - Justin
对于我的使用情况,我会选择在将其传递给std::variant之前使类型唯一化。用例是检测某些临时结果的类型并将它们存储在上下文中。我选择使用std::array<std::variant<unique types>, sizeof all types>作为内存持有者。这是代码:https://github.com/BowenFu/matchit.cpp/blob/98b0862fdd970832b6286b5c5f2959681977c1e4/develop/matchit/patterns.h#L261 - Bowen Fu
3
这是一个情况,我会将举证责任放在想要更多限制的人身上(即“保持简单”的相反情况)。为什么要通过限制std::variant可以保存哪些类型组合来使其变得更加复杂?允许更多的功能有什么问题吗?为什么要阻止将来有人发现一个用例呢? - JaMiT
2个回答

10

假设我们想要表示一个可以是关键字、标识符或符号的令牌。一种可能的实现方法如下:

enum TokenType : std::size_t {
    Keyword = 0, Identifier = 1, Symbol = 2
};

using Token = std::variant<std::string, std::string, char>;

现在可以使用,例如:

std::get<TokenType::Keyword>(token)

访问替代方案的方法。

当然,这是否是一个好主意存在争议,但它确实显示了这种用例的存在。


8

std variant旨在作为一种代数类型(sum type)在通用代码中使用。

它需要满足以下代数性质:当两个variant a和b进行合并时(其中只有一个是活动状态),如果a处于活动状态,那么合并后的结果的索引值应该等于a的索引值;如果b处于活动状态,那么合并后的结果的索引值应该等于a的备选项数量加上b的索引值。

因为除此之外的任何情况都可能变得很疯狂。

事实上,变量成员的名称是其索引,而不是类型。

您可以自由地编写一个禁止重复类型的variant别名以供您自己的代码使用。这相对容易实现。

如果我们基于具有命名的备选项的variant来编写程序,那么构建基于索引的variant就会变得非常麻烦。

使用反射技术也可以创建具有命名备选项的variant。如果我们阻止了具有重复类型的索引型variant,那么这将变得更加困难。


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