2016-03-29 3 views
23

Предположим, например, что вы хотите реализовать электронную таблицу Cell на C++. Ячейкой может быть строка, число или, возможно, пустое. Игнорируйте другие случаи, например, формулу.Что такое идиоматический современный C++ для алгебраических типов данных?

В Haskell, вы могли бы сделать что-то вроде:

data Cell = CellStr String | CellDbl Double | None 

Что считается в настоящее время «наилучшей практики» для делать это в C++? Использовать объединение в структуре с индикатором типа или что-то еще?

+10

Возможна одна опция ['boost :: variant'] (http://www.boost.org/doc/libs/1_60_0/doc/html/variant.html). – Pixelchemist

+0

или реализовать себе конкретный тип варианта с объединением –

+3

@Pixelchemist сделать это ответ, и я сделаю +1 его. –

ответ

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;} ' – user463035818

+0

Я не думаю, что это сработает, потому что вы не могли бы, например, иметь массив ячеек. – blippy

+0

@blippy: Да, но вы можете иметь массив (умных) указателей на ячейки. –

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

Тогда вы могли бы сделать что-нибудь с клеткой с:

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

Также обратите внимание, что есть предложение о стандартизации ['std :: variant'] (http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0088r1.html) (исходное предложение [здесь ] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4218.pdf)) – filipos

+0

@filipos, на мой взгляд, это предложение ошибочно, поскольку оно требует мандата, позволяющего варианту быть пустым. Я искренне надеюсь, что он отвергнут в пользу того, который более точно моделирует вариант повышения. –

+2

В последней версии этого не предусмотрено. Чтобы использовать пустое состояние, вы явно добавляете тип «monostate» в список типов. Это правда, хотя вариант может стать недействительным (не пустым) в исключительных условиях. – filipos

-1

Стандартный способ реализации полиморфизма виртуальных классов. http://www.cplusplus.com/doc/tutorial/polymorphism/

Это основной механизм C++.

+5

Полиморфизм - это правильный подход, когда все предметы являются специализацией концепции, а все специализации имеют общий интерфейс. Вне этого узкого размаха, он не приносит ничего, кроме проблем, –

+2

Нет такого понятия, как «виртуальный класс». –

+5

Это просто необъяснимая версия [Отца Фрэнка Паффера] (http://stackoverflow.com/a/36283593/2069064), нет? – Barry