2017-08-07 46 views
0

調用其他構造比方說,我有一個名爲類,並在網我有不同的靜態方法,如構造,不同的簽名

static Mesh makeTriangle(...) 

一些參數。然後我也有:

  • static Mesh makeBox(...):不同類型和參數比makeTriangle號碼,

  • static Mesh makeSphere(...):與完全相同相同類型和參數比makeTriangle號等

如何創建一個構造函數,該構造函數將const std::string &name作爲第一個參數和可傳遞給的可變數量的參數創建Mesh對象的右側「make」方法?
這是可能的在c + + 11?

我試圖用這樣的

template<typename... Params> 
Mesh(const std::string &name, Params&&... parameters) 
    : Mesh(init(name, std::forward<Params>(parameters)...)) {} 

但在init方法的一些點可變參數模板我必須做一些像

template<typename... Params> 
static Mesh init(const std::string &name, Params&&... parameters) { 
    if(name == "box") return makeBox(std::forward<Params>(parameters)...) 
    if(name == "sphere") return makeSphere(std::forward<Params>(parameters)...) 
    /* and so on */ 
} 

,編譯器會拒絕編譯,因爲參數包可能與某些make方法參數不匹配。我不能將它放在一個接受字符串並輸出函數指針的映射中,因爲所提及的make方法具有不同的簽名。
那麼我又能如何在C++ 11中做到這一點?

編輯
我想用繼承來爲每個不同的形狀subclases不會是因爲所有網格對象基本上是在空間中的點列表的最佳選擇,它們都是同一個類的對象,他們的唯一途徑不同之處在於它們的構建方式

+0

顯示實際的代碼。 –

+0

第一個參數是否必須是字符串? – ecatmur

+0

@ecatmur我想。構造函數如何調用正確的make方法? – user5667542

回答

0

您已經錯過了整個繼承點。這一點基本上是,你保留所有常見的東西在Shape(如位置),並保持一切形狀特定於子類。

首先,構建像三角形和矩形等多邊形時,類似於半徑(對於基於π的形狀(例如圓形和球體)至關重要)具有位置。

在僞代碼,你應該做的是:

class shape: 
    float x_coord 
    float y_coord 

class rectangle: inherits shape 
    float width 
    float height 

class circle: inherits shape 
    float radius 

然後你構建具體形狀,而不是更抽象的。這些作爲shape的子類的具體形狀應該能夠使用所有常見的東西以及它們在繼承期間添加的東西。

+0

我發佈的代碼就是一個例子,在實際代碼繼承(據我所知)確實是沒有用的。但我認爲這是一個不好的例子,我會改變 – user5667542

+1

@ user5667542的問題,我的專業觀點是你應該重新考慮你的觀點:「繼承真的沒有用處」。如果確實如此,那麼你將會有*無*理由試圖去做(有一個類代表不同的類型)。構造在類型之間具有相似性的事實幾乎是保證繼承正是你所需要的。 – paxdiablo

+0

當然,您可能有額外的信息讓您相信這一點。在這種情況下,我會要求你分享它。不透明使得我們難以協助除模糊概括以外的任何事情。 – paxdiablo

1

而不是使用一個字符串,你應該使用一個標籤,比如標籤類:

struct box {}; 
struct sphere {}; 

template<class Tag, typename... Params> 
static Mesh init(Tag, Params&&... parameters) { 
    if constexpr (std::is_same<Tag, box>::value) return makeBox(std::forward<Params>(parameters)...) 
    else if constexpr (std::is_same<Tag, sphere>::value) return makeSphere(std::forward<Params>(parameters)...) 
    /* and so on */ 
} 

然後你的用戶將調用構造函數例如Mesh{box{}, a, b, c}

作爲一個標籤類的替代方案,你也可以使用一個枚舉和integral_constant

enum class MeshName { Box, Sphere, ... }; 

template<class Name, typename... Params> 
static Mesh init(std::integral_constant<MeshName, Name>, Params&&... parameters) { 
    if constexpr (Name == MeshName::Box) return makeBox(std::forward<Params>(parameters)...) 
    else if constexpr (Name == MeshName::Sphere) return makeSphere(std::forward<Params>(parameters)...) 
    /* and so on */ 
} 

如果您name參數必須是一個字符串,你唯一的選擇是延遲參數檢查,運行時間和問題運行時錯誤:

template<typename... Params> 
static Mesh init(const std::string &name, Params&&... parameters) { 
    if(name == "box") 
     if constexpr (std::is_invocable<decltype(makeBox), Params...>::value) 
      return makeBox(std::forward<Params>(parameters)...) 
     else 
      throw std::invalid_argument("Incorrect arguments for makeBox"); 
    if(name == "sphere") 
     if constexpr (std::is_invocable<decltype(makeSphere), Params...>::value) 
      return makeSphere(std::forward<Params>(parameters)...) 
     else 
      throw std::invalid_argument("Incorrect arguments for makeSphere"); 
    /* and so on */ 
} 
+1

不是帶有'如果constexpr'的C++ 11解決方案。 – MSalters

+0

在C++ 11程序員將被迫創建單獨的模板。另外,我知道只有C++ 17的實現對代碼生成非常不利。但總的來說這還是比在大多數情況下字符串更好,除非我們處理一些文本輸入,比如以文本形式提供的參數\屬性.. – Swift

+0

@MSalters翻譯,以傳統的C++語法11是非常簡單的,雖然。沒有看到需要過分複雜的代碼。 – ecatmur