现代C++中关于代数数据类型的惯用写法是什么?

30
假设,例如,您想在C++中实现电子表格单元格。单元格可以是字符串、数字或空白。忽略其他情况,比如它是一个公式。
在Haskell中,你可能会这样做:
data Cell = CellStr String | CellDbl Double | None

在C++中,目前被认为是最佳实践的做法是什么?在结构中使用联合和类型指示器,或者其他方法?


10
一种可能的选择是 boost::variant - Pixelchemist
3
将其翻译为:@Pixelchemist 把那个作为答案,我会点赞它。 - Richard Hodges
1
我会选择一个已排序的 vector<pair<XYCoords, double>> doubles; 和一个已排序的 vector<pair<XYCoords, string>> strings;。对于给定的单元格坐标,您可以在 doubles 中使用 lower_bound,如果找不到,则在 strings 中执行相同操作,否则为 None。绘制屏幕应该非常快,您只需遍历 vector 即可。计算有点混乱,因为它们取决于类型,但您可能可以将其抽象化。实际上,我只是作弊了,从未将不同类型组合成一个。无论如何,这个问题太广泛和主观了。 - nwp
1
@MvG 很遗憾,Haskell的高亮代码是lang-hs而不是lang-haskell。下次您想要添加Haskell代码的高亮时请记住这一点。 - Bakuriu
链接(因问题已关闭):https://gist.github.com/czipperz/ca36868273d193b48ec7edcc84051e6e - Czipperz
显示剩余4条评论
2个回答

24
struct empty_type {};
using cell_type = boost::variant<std::string, double, empty_type>;

那么您将使用以下单元格进行某些操作:

boost::apply_visitor(some_visitor(), cell);

2
还要注意,有一个提案正在标准化std::variant(原始提案在此)。 - filipos
在我看来,这个提案存在缺陷,因为它试图强制允许一个变量为空。我真诚地希望它被拒绝,而是采用更接近boost变量的模型。 - Richard Hodges
2
最新版本不强制要求这样做。要使用空状态,您需要将类型“monostate”明确添加到类型列表中。但是,在异常情况下,变量确实可能变为无效(非空)。 - filipos
3
在我看来,他们似乎混淆了问题。可选是一个问题,变体是另一个问题。如果提议者想要一个可选的变体,他可以使用optional<variant<...>>。即使经过移动,变体也不应该被允许无效,它应该只包含一个已移动的T。 - Richard Hodges
4
LEWG决定不引入一个显式的额外变量状态,用于表示其无效(可能为空、默认构造的)状态。 - filipos
显示剩余11条评论

5

继承?

我必须说,我并不是很喜欢这种方法,也不认为它是现代的,但它似乎仍然是标准的。

class DoubleCell : public Cell {
    double value;

    public:
    DoubleCell( double v ) : value(v) {}
    double DoubleValue() { return value; }
    ...
};

class StringCell : public Cell {
    std::string value;

    public:
    StringCell( std::string v ) : value(v) {}
    std::string StringValue() { return value; }
    ...
};

class EmptyCell : public Cell {
    ...
};

一些缺点包括:

  • 获取实际值时,需要使用不同的函数。这通常涉及使用 instanceof 和强制类型转换。

  • 不同的对象不能直接放入容器中,只能作为指针。


1
这只是部分回答了问题。你如何从这样的单元格中获取值 ??? getValue(){return value;} - 463035818_is_not_a_number
2
指针语义、动态内存分配以及为每个单元格进行虚函数调用对我来说似乎不是一个好主意。 - nwp
2
模版在这个例子中并不能真正起作用(至少在实现的方式上),因为每个单元格的类型需要在编译时进行确定。我猜你可以通过让模版继承一个公共的基类来结合这两种方法,但这样做会产生与第一种方法相同的性能负担。 - interjay
2
@FrankPuffer 使用库只是为了避免他们自己编写代码。在您的示例中,您将如何获取单元格中的值?在您解决这个问题之前,这只是半个答案。 - NathanOliver
3
我认为这个答案不应该被删除。 它是一个合理的设计解决方案,值得讨论,即使只是说有更好的解决方案。 - blippy
显示剩余8条评论

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