2010-01-03 66 views
0

模板允許C++自動創建許多具有相同接口但存儲不同數據的類。C++使用不同的字段組合創建類的變體

我正在尋找類似的東西(我不知道它是否存在,這就是爲什麼我問這裏),它會自動爲我創建一個對象的變體,只存儲數據成員的一個子集。

比方說,我有一個

class FullClass 
{ 
public: 
    bool A; 
    int B; 
    float C; 
    double D; 
}; 

的話,我想有例如像這些領域的所有可能的組合:

class BDClass 
{ 
public: 
    int B; 
    double D; 
}; 

class BCDClass 
{ 
public: 
    int B; 
    float C; 
    double D; 
}; 

,我想能夠從任何變體類投射到FullClass,使得定義的字段將被複制,a第二缺失字段設置爲defaultvalues:

FullClass foo; 
BDClass bar = BDClass(3, 5.0); 
foo = (FullClass) bar; 

有沒有讓編譯器創建這些變化對我來說,還是我來定義所有可能的組合自己的任何機制?

謝謝!

編輯:

我爲什麼要找這個?

我有一個遵循策略模式的軟件構造。因此,我有一堆使用相同接口的不同算法(超過30個)。客戶端應該能夠使用該接口而不知道當前正在運行的確切算法。客戶端計算這樣一個'FullClass'對象並將其傳遞給接口 - 但是,每個算法僅使用此對象中提供的字段的子集(並且每個算法使用不同的字段)。 這個策略模式構造是固定的,我不能改變它。

現在我想'記錄'這樣生成的'FullClass'對象的序列,這樣就可以重複使用這個構造的完整流程而不必重新計算那些'FullClass'對象。然而,這是很多數據(我想保留在mainmemory出於性能的原因),並且由於大多數算法只使​​用一小部分字段,我只想存儲有效使用的字段

+1

不是。這可能是一個好主意,通過這樣解釋你想要解決什麼問題。 – 2010-01-03 15:34:41

+0

請注意,使屬性公開是一個壞主意。使他們私密,並添加setter和getters。 – 2010-01-03 15:51:08

+0

Neil:請閱讀我的編輯以獲得解釋 – genesys 2010-01-03 15:58:04

回答

1

我甚至不能想象爲什麼你需要這個,但你可以嘗試使用混入:

class Dummy 
{ 
}; 

<template Base> 
class AClass : public Base 
{ 
    public: 
      bool A; 
}; 

<template Base> 
class BClass : public Base 
{ 
    public: 
      int B; 
}; 

... //(etc) 

BClass< AClass<Dummy>> abClass; 
abClass.B = 4; 
abClass.A = false; 

如果你堅持下去,你將能夠做到:

DClass< CCLass< BClass< AClass<Dummy>>>> abcdClass; 
+0

這看起來很整潔!我會嘗試的! – genesys 2010-01-03 16:02:44

+0

它也可以將一個變量從例如abClass轉換爲abcdClass? – genesys 2010-01-03 16:39:51

+0

我的第一意圖是說不,但實際上需要驗證,因爲它是有道理的,它應該是可能的。假設你應該能夠將abcdClass分配給abClass。 – 2010-01-03 16:56:44

0

首先,你可以爲每個數據類型定義四個類,然後爲類型對聲明templae類,然後爲三個類聲明類型組合,然後是四個。你不能比這更簡單。

+0

它不符合轉換條件。 – 2010-01-04 19:30:26

0

我想你可以使用私有類數據模式做一些事情,然後是一些可怕的存儲器複製技巧:

class Full 
{ 
private: 
    struct fullData 
    { 
     a; 
     b; 
     c; 
     d; 
     e; 
     ... 
     z; 
    } * m_pData; 
public: 
    Stuff! 
} 

class Partial 
{ 
private: 
    struct partialData 
    { 
     a; 
     b; 
     c_filler; //This is an issue 
     d; 
    } 
public: 
    Different Stuff!; 
} 

然後,當你複製,只是從字面上複製partialData的內存分爲fullData,填補了休息全零數據的零。

問題是,這隻適用於不需要你使用構造函數的數據類型(因此,這裏沒有安全檢查),並且必須放入填充(如上)以確保數據正確排列。

但你的拷貝構造函數獲取要一個存儲器複製然後memfill; (注意,我幾乎可以肯定有存儲器複製並填寫語法錯誤)

template<class T> 
Full(T& t) 
{ 
    m_pData = new fullData; 
    memcopy(/*to*/m_pData, /*from*/Partial->getData(), /*how much to copy*/ sizeof(T)); 
    memfill(/*tp*/m_pData, /*how much to copy*/ sizeof(fullData) - sizeof(T), /*with*/ 0); 
} 

可能對您的特定情況下工作,但它不是特別安全或相當。

0

你有沒有考慮過編寫一個預處理程序來codegen你需要什麼?

+0

我想我需要某種形式的for-loop在預處理器中創建它 - 是否有預處理器指令來執行循環? – genesys 2010-01-05 18:34:57

+0

不,我的意思是編寫自己的代碼代碼。也許使用預處理器這個詞是不正確的。 – 2010-01-05 18:56:57

0

我個人很欣賞Boost.Fusion;)

在這裏,我會用boost::fusion::map,因爲它允許很容易地混合類型。

您需要使用標籤的類型組合(類型僅用於編譯目的)和實際類型,用來存儲數據。

讓我們來定義標籤:

class a_tag { typedef bool type; }; 
class b_tag { typedef int type; }; 
class c_tag { typedef float type; }; 
class d_tag { typedef double type; }; 

然後你就可以編寫使用Boost.Preprocessor宏這需要的標籤列表,並生成相應的boost::fusion::map

GENERATE_MY_TYPE(TypeName, (a_tag)(b_tag)(c_tag)(d_tag)); 

// For information: (a_tag)(b_tag)(c_tag)(d_tag) is called a sequence in PP 

類型應該是這樣的:

typedef boost::fusion::map< 
    std::pair<a_tag, a_tag::type>, 
    std::pair<b_tag, b_tag::type>, 
    std::pair<c_tag, c_tag::type>, 
    std::pair<d_tag, d_tag::type> 
> TypeName; 

或者更有可能使用包裝boost :: fusion :: map作爲實現細節,例如:

// defined once 
template <class Vector> 
struct TemplateType 
{ 
    typedef Vector tags_type; 
    typedef detail::deduce<Vector>::type data_type 
// which for Vector = boost::mpl::vector<a_tag, b_tag, c_tag, d_tag> should be 
// typedef boost::fusion::map< 
// std::pair<a_tag, a_tag::type>, 
// std::pair<b_tag, b_tag::type>, 
// std::pair<c_tag, c_tag::type>, 
// std::pair<d_tag, d_tag::type> 
// > data_type; 

    data_type m_data; 

    template <class T> 
    boost::fusion::result_of::at<T, data_type> at() 
    { 
    return boost::fusion::at<T>(m_data); 
    } 
}; 

// Generated by the macro, filling boost::mpl::vector by iteration 
// the sequence 
typedef TemplateType< boost::mpl::vector<a_tag, b_tag, c_tag, d_tag> > TypeName; 

然後,您只需要定義的類型以提供來自標記子集的轉換技巧。如果您只需要擁有完整的子集,則只能定義一次。

template <class Vector> 
TypeName toTypeName(TemplateType<Vector> const& arg) 
{ 
    TypeName result; 
    result.fill(arg); 
    return result; 
} 

隨着填充被定義爲:

namespace detail 
{ 
    class NoAssign 
    { 
    template <class Pair, class TT> static Do(Pair const&, TTconst&) { } 
    }; 

    class Assign 
    { 
    template <class Pair, class TT> 
    static Do(Pair& p, TTconst& tt) 
    { 
     p.second = tt.at<typename Pair::first_type>(); 
    }; 
    }; 

    template <class Vector> 
    class Filler 
    { 
    public: 
    Filler(TemplateType<Vector> const& ref): m_ref(ref) {} 

    template <class T, class U> 
    void operator()(std::pair<T,U>& p) const 
    { 
     typedef typename boost::mpl::find<T,Vector>::type it; 
     typedef typename boost::mpl::end<Vector>::type end; 

     typedef typename boost::mpl::if< boost::same_type<it,end>, NoAssign, Assign> assign; 

     assign::Do(p, m_ref); 
    } 

    private: 
    TemplateType<Vector> const& m_ref; 
    }; 
} 

template <class Vector> 
template <class OV> 
void TemplateType<Vector>::fill<OV>(TemplateType<OV> const& rhs) 
{ 
    boost::fusion::for_each(m_data, detail::Filler<OV>(rhs)); 
} 

我愛這些問題,當然,被迫使用這兩個模板元和預設電臺預處理生成一些模板類/方法...意味着一些冗長的解決方案和一些頭痛。一旦完成,但語法可以非常簡潔(對於用戶)。

+0

看起來很花哨 - 我沒有得到任何東西 - 但我不認爲這個好聽的POD結構只存儲我需要的成員值,是嗎? – genesys 2010-01-05 18:25:18

+0

不管他們是否POD都是實施問題,我不清楚Fusion是如何在封面背後實施的。一個快速測試往往證明'fusion :: map'是相應結構的兩倍大。 – 2010-01-05 19:28:29

相關問題