2013-03-14 38 views
3

我知道這個問題可能非常含糊,而且對於我給出的答案here有點延伸。基本上,作爲一個個人項目,我一直試圖複製「代碼優先」成語,這在C#程序員做數據庫工作時非常流行,但在C++中。一切都很好,運作良好。將模板類初始化爲基類的一個很好的方法

關於C#的一件偉大事情就是屬性等事情。我們並沒有在C++中是新穎性,所以我對於一個特定的類,然後在數據庫結構,代碼如下:

class User : public Record { 
public: 
    User(Model& m) : Record(L"_user", m) 
        , Username(L"_userName", 32, false) 
        , Nickname(L"_nickName", 32, false) { 
     field(Username); 
     field(Nickname); 
    }; // eo ctor 

    Field<String> Username; 
    Field<String> Nickname; 
}; // eo class User 

理想情況下,我想在構造函數中擺脫field電話。他們所做的一切本質上都是將該領域註冊到基礎課程中,然後開展真正的工作。我該如何完成這種事情,並將細節傳遞給基類,就像我在構造函數中指定的那樣?

在上一個問題I answered我能夠給出的基類信息感謝C++構造的東西。有沒有一種方法可以在構造函數中利用這一點,並擺脫可能引入程序員錯誤的討厭field調用?

在這一點上,我很高興,一切都很好,但我很想減少混亂,並在構造函數中刪除這個「註冊」過程的需要,並以某種方式讓它們自動註冊到基類。歡迎

所有意見:)

編輯

field的implentation正是如此:

 void Record::field(detail::field_base& field) { 
      field.owner_ = this; 
      fields_.push_back(&field); 
     }; // eo field** 
+1

這將有助於如果你能夠顯示'field()'實際做了什麼以及它是哪個類的成員('Record',我想,但這只是一個猜測) – 2013-03-14 00:05:45

+0

@AndyProwl,我已經修改了題。除了將其推入稍後的推薦列表之外,它幾乎沒有什麼用處。 – 2013-03-14 00:08:50

回答

4

你可以有Field<>構造函數接受額外的指針Record並在構造函數的身體指針調用field(*this)

template<typename T> 
struct Field // Just guessing... 
{ 
    Field(std::string s, int i, bool b, Record* pRecord) 
    // ... 
    { 
     pRecord->field(*this); 
    } 
    // ... 
}; 

然後,在User你的初始化列表,你會通過this作爲附加Record指針,這種方式:

User(Model& m) : Record(L"_user", m) 
       , Username(L"_userName", 32, false, this) 
       , Nickname(L"_nickName", 32, false, this) 
{ 
}; // eo ctor 
+0

哇,我可能會錯過一些東西,但是......我的頭腦中認爲'this'在初始化過程中是無效的......當然這可能是我的錯誤。 – 2013-03-14 00:15:46

+1

@ Moo-Juice:在調用Record的構造函數時(構造函數是在基類之後構造的),基礎子對象已經被構造,所以這應該是格式良好的。 – 2013-03-14 00:17:13

+0

@ Moo-Juice在施工過程中要小心調用「虛擬」的功能(即使是間接的!)。並且避免做可能失敗的事情,除非你不能幫助它(在施工期間處理失敗令人討厭) – Yakk 2013-03-14 01:48:01

2

只是傳遞必要的信息,即你​​的this指針,到Field構造,並讓它做這項工作

,你甚至可能會引入一個特殊的包裝類此

2

不要被掛在屬性語法。

你想要的是將structs作爲具有運行時反射的有意義命名的數據聚合的能力,是正確的嗎?

推出新的名稱,使用類型:

template<typename T> struct FieldTag {}; 
struct Username:FieldTag<Username> {} username; 
struct Nickname:FieldTag<Nickname> {} nickname; 

爲了生產類型的集合,使用模板參數:

template<typename Child, typename Field> 
struct FieldHandler { 
    typedef typename Field::tag_type tag_type; 
    typedef typename Field::value_type value_type; 
    PsuedoRef<value_type> operator[](tag_type) { /* details */ } 
    /* details */ 
}; 
template<typename... Fields> 
struct Aggregate: 
    Record, 
    FieldHandler<Aggregate<Fields...>, Fields>... 
{ 
    /* details */ 
}; 
template<typename Value, typename Tag> 
struct Field { 
    typedef Tag tag_type; 
    typedef Value value_type; 
}; 

上述所有樣板的目標,再加上一些操作符重載濫用,我們可以從中得到一些漂亮的語法,而最終的程序員得到的語法看起來很像C++,沒有樣板。

這裏是你如何創建一個Data型兩個領域的最終目標:

struct Data: 
    Aggregate< 
    Field<std::string, Username>, 
    Field<std::string, Nickname> 
    > 
{ 
    Data(): Aggregate(
    username|L"username" = L"Unknown Name", 
    nickname|L"nickname" = L"Unknown NickName" 
    {} 
}; 

訪問一個字段,使用適當的被覆蓋的運營商:(我喜歡^,它結合緊密,並期待有點像->

Data d; 
d^username= L"Bob"; 
d^nickname= L"Apples"; 

這是C++ 11的所有可能的,但它不是那麼容易。

現在,將指針指向函數作爲模板參數,以及可轉換爲函數的無狀態lambda可以讓我們將字符串存儲在字段類型中,而不需要在構造時傳遞它時間。另一方面,對未評估背景的限制使得這看起來值得懷疑。

所以這是一個醜陋的剩餘。另外,爲了達到上述目的,所需的努力讓我覺得你可能應該在每個領域吞下令人討厭的樣板。

請注意,上面的代碼只是僞代碼,並且可以採用一條路線的草圖,而不是所有接近完成的路線。我建議不要試圖走下這條路,除非你想迷失在學習C++的模板元編程子語言的樹林中,並且永遠不會完成你的問題。

然後再次,不會學習模板元編程比您當前的項目更有趣嗎? ;)