объект переживающий свою сферу с ++ - PullRequest
0 голосов
/ 10 февраля 2019

Мне было интересно, существует ли способ для объекта пережить время жизни его области действия и все еще быть пригодным для использования, для случаев, подобных примеру, показанному ниже.Вообще говоря, я пытаюсь использовать объект другого типа в зависимости от входного параметра.Эта проблема может быть легко решена, если оператор if-else находится в той же области, что и вызов calc_force, но это, безусловно, будет препятствовать производительности программы.

Я рассмотрел несколько возможных решений с использованием std::function и std::shared_ptr, но безрезультатно.Я не уверен, что даже подхожу к этой проблеме с правильным мышлением, используя обертки классов для MD_tools::GCM_force и MD_tools::GCM_force.Любая помощь будет принята с благодарностью.

std::tuple<double, double> GCM_pp::get_force(double &r, double m, double C) {
  auto [ff, u] = MD_tools::GCM_force(r, m, C);  // This is static
  return std::make_tuple(ff, u);
}

std::tuple<double, double> Exp_pp::get_force(double &r, double m, double C) {
  auto [ff, u] = MD_tools::Exp_force(r, m, C);  // This is static
  return std::make_tuple(ff, u);
}

void simulate(std::string pp_type, size_t step, double POWER, double A_CST{
  // Normally the if-else loop contains a couple dozen if statements
  if (pp_type == "GCM") GCM_pp potential;
  else Exp_pp potential;

    for (step = 0; step < step_max; ++step) { // typical values: step ~1,000,000
      size_t i, j;
      for (i = 0; i < N - 1; ++i) { // typical values: N ~10,000
        for (j = i + 1; j < N; ++j) {
          // stuff happening ...
          double r = sqrt((x * x) + (y * y) + (z * z));       
          auto [ff, temp_u] = potential.calc_force(r, POWER, A_CST);
          // stuff happening ...
          }
        }
    }
}

1 Ответ

0 голосов
/ 10 февраля 2019

Это тот тип вещей, для которого могут использоваться полиморфизм и фабрики классов, например:

class Base_pp
{
public:
  virtual ~Base_pp() {}
  virtual std::tuple<double, double> get_force(double &r, double m, double C) = 0;
};

class GCM_pp : public Base_pp
{
public:
  std::tuple<double, double> get_force(double &r, double m, double C) override {
    auto [ff, u] = MD_tools::GCM_force(r, m, C);  // This is static
    return std::make_tuple(ff, u);
  }
};

class Exp_pp : public Base_pp
{
public:
  std::tuple<double, double> get_force(double &r, double m, double C) override {
    auto [ff, u] = MD_tools::Exp_force(r, m, C);  // This is static
    return std::make_tuple(ff, u);
  }
};

...

using funcType = std::unique_ptr<Base_pp> (*)();

std::map<std::string, funcType> make_funcs = {
  {"GCM", []() -> std::unique_ptr<Base_pp> { return std::make_unique<GCM_pp>(); }},
  ...
  {"Exp", []() -> std::unique_ptr<Base_pp> { return std::make_unique<Exp_pp>(); }}
};

std::unique_ptr<Base_pp> make_pp(std::string pp_type) {
  funcType func = make_funcs[pp_type];
  if (!func) func = make_funcs["Exp"];
  return func();
}

...

void simulate(std::string pp_type, size_t step, double POWER, double A_CST) {
  std::unique_ptr<Base_pp> potential = make_pp(pp_type);
  for (step = 0; step < step_max; ++step) { // typical values: step ~1,000,000
    size_t i, j;
    for (i = 0; i < N - 1; ++i) { // typical values: N ~10,000
      for (j = i + 1; j < N; ++j) {
        // stuff happening ...
        double r = sqrt((x * x) + (y * y) + (z * z));       
        auto [ff, temp_u] = potential->get_force(r, POWER, A_CST);
        // stuff happening ...
      }
    }
  }
}

В качестве альтернативы, вам на самом деле не нужен полиморфизм в вашем примере.Поскольку ваши классы не используют данные экземпляра, вы можете попробовать что-то более похожее на это:

class GCM_pp
{
public:
  static std::tuple<double, double> get_force(double &r, double m, double C) {
    auto [ff, u] = MD_tools::GCM_force(r, m, C);  // This is static
    return std::make_tuple(ff, u);
  }
};

class Exp_pp
{
public:
  static std::tuple<double, double> get_force(double &r, double m, double C) {
    auto [ff, u] = MD_tools::Exp_force(r, m, C);  // This is static
    return std::make_tuple(ff, u);
  }
};

...

using funcType = std::tuple<double, double> (*)(double&, double, double);

std::map<std::string, funcType> get_force_funcs = {
  {"GCM", &GCM_pp::get_force},
  ...
  {"Exp", &Exp_pp::get_force}
};

funcType get_force_func(std::string pp_type) {
  funcType func = get_force_funcs[pp_type];
  if (!func) func = get_force_funcs["Exp"];
  return func;
}

...

void simulate(std::string pp_type, size_t step, double POWER, double A_CST) {
  funcType get_force = get_force_func(pp_type);
  for (step = 0; step < step_max; ++step) { // typical values: step ~1,000,000
    size_t i, j;
    for (i = 0; i < N - 1; ++i) { // typical values: N ~10,000
      for (j = i + 1; j < N; ++j) {
        // stuff happening ...
        double r = sqrt((x * x) + (y * y) + (z * z));       
        auto [ff, temp_u] = get_force(r, POWER, A_CST);
        // stuff happening ...
      }
    }
  }
}

Или вот это:

class GCM_pp
{
public:
  static std::tuple<double, double> get_force(double &r, double m, double C) {
    auto [ff, u] = MD_tools::GCM_force(r, m, C);  // This is static
    return std::make_tuple(ff, u);
  }
};

class Exp_pp
{
public:
  static std::tuple<double, double> get_force(double &r, double m, double C) {
    auto [ff, u] = MD_tools::Exp_force(r, m, C);  // This is static
    return std::make_tuple(ff, u);
  }
};

...

template<typename T>
void do_simulate(size_t step, double POWER, double A_CST) {
  for (step = 0; step < step_max; ++step) { // typical values: step ~1,000,000
    size_t i, j;
    for (i = 0; i < N - 1; ++i) { // typical values: N ~10,000
      for (j = i + 1; j < N; ++j) {
        // stuff happening ...
        double r = sqrt((x * x) + (y * y) + (z * z));       
        auto [ff, temp_u] = T::get_force(r, POWER, A_CST);
        // stuff happening ...
      }
    }
  }
}

using funcType = void (*)(size_t, double, double);

std::map<std::string, funcType> simulate_funcs = {
  {"GCM", &do_simulate<GCM_pp>},
  ...
  {"Exp", &do_simulate<Exp_pp>}
};

funcType get_simulate_func(std::string pp_type) {
  funcType func = simulate_funcs[pp_type];
  if (!func) func = simulate_funcs["Exp"];
  return func;
}

...

void simulate(std::string pp_type, size_t step, double POWER, double A_CST) {
  funcType simulate_func = get_simulate_func(pp_type);
  simulate_func(step, POWER, A_CST);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...