Предоставление возможных параметров различных типов в статически типизированном языке - PullRequest
0 голосов
/ 07 апреля 2020

Скажем, у меня есть class Action, который хранит некоторые Guy с и вовлекает их в действие через некоторое время:

class Action {
  std::vector<Guy> guys;

  void bring() {
    Guy newcomer = guys.back();
    switch (newcomer.characteristic) {
      // see below
    }
  }

  // ...
};

Вот проблема с этим switch: у парня может быть черта, которая может нуждаться в каком-либо дополнительном объяснении или может не нуждаться ни в каком. Например:

case loser: // no more information needed to continue
  banish(guy);
  break;
case buddy:
  Guy buddy = newcomer.whose(); // the "explanation" which is needed for this case
  if (is_here(buddy)) {
    newcomer.happiness += 42;
  }

Как я могу разумно хранить информацию, которая может понадобиться? К сожалению, у него могут быть разные типы (с точки зрения языка программирования), поэтому предоставление членов класса для каждого возможного перечислителя не представляется хорошо масштабируемым вариантом и подвержено ошибкам из-за простоты совершения неподходящих вызовов:

enum Characteristic { // isn't "enum class" for brevity of the example
  buddy, gourmet, loser, // etc.
};
class Guy {
 public:
  Characteristic characteristic;

  Guy whose() {
    if (characteristic != buddy) {
      throw std::logic_error("inappropriate call"); // awful!
    }
    return this->buddy;
  }
  Food favorite() { // for "gourmet"
    // same as above?!
  }
  // etc.
};

Я думал о наследовании, но ничего не придумал. Лучшая идея выглядит как

void Derived_guy::be_brought(Action& action) {
  // modify action in any way
}

Однако для того, чтобы узнать Action, что является старшей абстракцией - плохой дизайн, требуется Guy.

Как еще можно решить мою проблему?

1 Ответ

2 голосов
/ 07 апреля 2020

Вы можете заменить свой enum на std::variant, в котором может храниться любая информация:

struct Buddy
{
    Guy whose;
};

struct Loser{};

struct Gourmet
{
    Food favorite;
};

// ...

using Characteristic = std::variant<Buddy, Loser, Gourmet>;

class Guy {
public:
    Characteristic characteristic;
};

И, наконец,

struct MyVisitor
{
    Guy& newcomer;

    void operator()(Loser) const { banish(newcomer); }
    void operator()(Buddy& buddy) const
    {
        if (is_here(buddy.whose())) {
            newcomer.happiness += 42;
        }
    }
    // ...
};

void bring() {
    Guy newcomer = guys.back();

    std::visit(MyVisitor{newcomer}, newcomer.characteristic);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...