簡體   English   中英

C ++在運行時從設置中選擇類型

[英]c++ choose type from set at runtime

我有一個程序,我想在運行時而不是編譯時從預定義列表中選擇一組類型。

下面是我想運行的那種代碼的示例; EvenLog是定義數字網格的類型,而deriv_Ox是x階的微分方案:

struct Even {
  double a, b;
};
struct Log {
  double a, x0, b;
};
// ...

struct deriv_O2 {
  vec_type operator() (const vec_type & f_points) const;
};
struct deriv_O4 {
  vec_type operator() (const vec_type & f_points) const;
};
// ...

template <class grid_type, class deriv_type>
void run_calculation (const std::string param_file) {
  auto grid  =  grid_from_file<grid_type>(param_file);
  auto deriv = deriv_from_file<deriv_type>(param_file);
  // ...
}

我想通過讀取參數文件來決定在運行時使用哪種類型。 我的解決方案是使用標簽和case語句從單個列表中確定要使用的類型,然后將每個case語句嵌套在一個函數中,以決定集合中的每種類型,如下所示:

enum struct grid_tag { Even, Log };
enum struct deriv_tag { O4, O2 };

grid_tag grid_tag_from_file (const char file_name[]);
deriv_tag deriv_tag_from_file (const char file_name[]);

template <class deriv_type>
void run_calculation (const grid_tag g,
                      const std::string param_file) {
  switch(g) {
  case grid_tag::Even:
    run_calculation<Even, deriv_type>(param_file);
    break;
  case grid_tag::Log:
    run_calculation<Log, deriv_type>(param_file);
    break;
  }
}

void run_calculation (const grid_tag g, const deriv_tag d,
                      const std::string param_file) {
  switch(d) {
  case deriv_tag::O4:
    run_calculation<deriv_O4>(g, param_file);
    break;
  case deriv_tag::O2:
    run_calculation<deriv_O2>(g, param_file);
    break;
  }
}

int main (int argc, char * argv[]) {
  grid_tag g = grid_tag_from_file(argv[1]);
  deriv_tag d = deriv_tag_from_file(argv[1]);
  run_calculation(g, d, argv[1]);
}

問題是我從〜10大小的列表中選擇了〜6種類型,並且將來會越來越多。 我目前的解決方案使添加新類型變得很尷尬。

這個解決方案是我要做的最好的選擇嗎? 我是不是很挑剔,還是有人可以建議更好的解決方案? 我已經看過boost :: variant(在類似問題中建議使用),但是我認為這真的不適合我想做的事情。

如所寫,這導致“雙重調度”,這在C ++中不容易解決(例如,請參見此處: 了解雙重調度C ++ )。

在這種情況下可能適用的方法,而不是:

template <class grid_type, class deriv_type>
void run_calculation (const std::string param_file) {
  auto grid  =  grid_from_file<grid_type>(param_file);
  auto deriv = deriv_from_file<deriv_type>(param_file);
  // ...
}

從文件中檢索網格/派生並產生具體類型,

void run_calculation (const std::string param_file, grid_tag gtag, deriv_tag dtag) {
  auto /*Grid interface*/ grid  = grid_from_file(param_file, gtag);
  auto /*Deriv interface*/ deriv = deriv_from_file(param_file, dtag);
  // ...
}

並在Grid / Deriv接口上使用虛擬函數調用來完成任務。

(如果您不想通過虛擬方法污染原始的網格/派生類,則還可以為其創建包裝器)

這樣做的好處(當然,如果適用於您的實際情況)將是您不需要解決所有組合。 與“開關”解決方案(以類似的方式工作)相比,您無需記住到處都放置開關來確定類型,您只需調用適當的虛函數即可完成工作(如果virt。函數是純粹在接口中,您不能忘記提供它們,因為否則它將無法編譯)。

另外,您可以在接口上提供一個虛擬方法來代替grid_tag,deriv_tag,以適當地從文件中讀取數據。

而且我還建議通過const ref(“ const std::string & param_file ”)傳遞字符串,而不是通過值(已復制)傳遞字符串。

從運行時值中選擇類型本質上涉及一些麻煩,但是從提供的代碼段來看,函數表可以正常工作

enum struct grid_tag { Even, Log, size };
enum struct deriv_tag { O4, O2, size };

using calculation = void (*)(std::string);

calculation table[grid_tag::size][deriv_tag::size];  // populate them

void run_calculation (const grid_tag g, const deriv_tag d, const std::string& param_file)
{
    table[g][d](param_file);
}

您可以解決此問題,以創建多個接口(未實現任何方法的抽象虛擬類),每種接口都可以在運行時確定。

然后,您可以使用模板方法模式通過已編寫的接口來編寫算法。

這樣,將元素添加到類型列表中只是在添加實現該接口的新類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM