2013-04-20 40 views
0

我需要一種通用的方法來創建任何類型的實例。這個任務需要從一個非模板對象進行的,所以我目前使用像這樣的接口:構造函數參數通過接口轉發

class Interface 
{ 
public: 
    virtual void PlacementCopy(void *data, const void *src) const = 0; 
    virtual void PlacementNew(void *data) const = 0; 
    virtual void PlacementDelete(void *data) const = 0; 
    virtual void Delete(void *data) const = 0; 
    virtual void Copy(void *dest, const void *src) const = 0; 
    virtual void NewCopy(void **dest, const void *src) const = 0; 
    virtual void *New() const = 0; 
}; 

這是全部拆開一個自定義的反射系統,並因此被這樣使用:

int *p = META(int)->Interface->New(); 
*p = 10; 

這通過創建模板化對象從Interface導出,它保存待構造的類型。的操作者New在界面確實的類型的默認構造:

template <typename T> 
class Derived : public Interface 
{ 
    virtual void *New(void) const override 
    { 
    return new T(); 
    } 
}; 

問題: 的所有類型的以這種方式必須提供一個默認的構造來構成。我想以某種方式允許任意參數傳遞給有問題的類型的構造函數。

不知何故,我需要能夠做到:

MetaInfo *meta = META(SomeType); 
SomeType *object = meta->New(arg1, arg2); 

這或許會是這個樣子的實現:

template <typename T> 
Derived : public Interface 
{ 
    template <typename ... Args> 
    virtual void *New(Args&& ... args) const override 
    { 
    new T(std::forward<Args>(args) ...); 
    } 
}; 

MetaInfo對象不是一個模板類型,這使得它很難提出一個參數轉發解決方案。我不能簡單地模擬Derived類中的New方法,因爲您無法模擬虛擬方法。

即使沒有一些瘋狂的代碼預處理,我甚至可能會問什麼?

+0

你可以使用一個代碼生成器或預處理器(最有可能的[Boost.Preprocessor](http://www.boost.org/doc/ libs/1_53_0/libs/preprocessor/doc/index.html))爲不同數量和類型的參數生成一個瘋狂的重載。 – Angew 2013-04-20 16:24:42

+0

哈哈,如果可能的話,我寧願不做代碼預處理。如果可以避免的話,不需要增加預構建步驟。它使構建過程複雜化,並增加了無法預料的代碼維護潛力。 – RandyGaul 2013-04-20 16:26:52

+0

如果你的元對象用一個單一的'int'參數描述一個類,並且有人調用'meta-> New(「thank you」,42.0)'',你會發生什麼?它應該是編譯時錯誤,運行時錯誤還是什麼? – 2013-04-20 16:37:56

回答

0

我最終在一些朋友的幫助下收集了一個解決方案!

所以最大的問題是所有要在反射中註冊的類型都需要默認構造函數。爲了解決這個問題,你可以使用SNIFAE來檢查默認構造函數的存在。

struct HasDefaultCtor 
{ 
    template <typename U> 
    static int32 SFINAE(decltype(U()) *); 
    template <typename U> 
    static int8 SFINAE(...); 

    static const bool value = sizeof(SFINAE<T>(NULL)) == sizeof(int32); 
}; 

除此之外所有非默認構造將必須用手工在反射系統中註冊,或與預生成步驟工具生成的。額外的SNIFAE檢查可用於類型檢查,並確保註冊的構造函數實際上匹配類中的實際構造函數。對於實際調用New運算符,需要進行一些運行時解析,以便確定需要哪些構造函數來與New調用進行匹配。

我希望這是有道理的,並最終對未來某個人有用。

我也做了拷貝構造一個SNIFAE檢查:

template <typename T> 
struct HasCopyCtor 
{ 
    static T MakeT(void); 

    template <typename U> 
    static int32 SFINAE(decltype(U(MakeT())) *); 
    template <typename U> 
    static int8 SFINAE(...); 

    static const bool value = sizeof(SFINAE<T>(NULL)) == sizeof(int32); 
}; 
+0

C++ 11已經具有這些類型特徵檢查器(參見,例如http://en.cppreference.com/w/cpp/types/is_default_constructible)。 – bluescarni 2013-04-21 11:30:34

+0

當然,但他們沒有檢查更高級的東西,比如特定數量的參數。 – RandyGaul 2013-04-21 22:05:56