2011-12-03 80 views
0

我正在研究C++ 11中的類型描述符項目。類型描述符的工作是知道類中每個成員的類型,它的大小和它從對象的底部偏移。我不支持多重繼承以及具有虛擬方法的對象,所以我現在使這更簡單了。目標是能夠使用描述符序列化和反序列化對象。指針到成員,類型描述符和引用

請注意,這是一個寵物項目,可以使用像variadic模板,指向成員的指針以及我不熟悉的C++的其他功能,所以不需要指向像boost :: archiveing之類的東西。 :)

我實際註冊成員的方式非常類似於boost :: python :: class_的方式。

ClassDescriptor fooDesc("Foo"); 
fooDesc.addMember("a", &Foo:: a); 
fooDesc.addMember("b", &Foo:: b); 

// (abridged for clarity) : 
template< typename ClassType, typename MemberType > 
ClassDescriptor& ClassDescriptor::addMember(
    const char* name, 
    MemberType ClassType::* member 
) 
{ 
    return addMember<MemberType>(name, reinterpret_cast<size_t>(&(((ClassType*)0)->*member))); 
} 

不幸的是,C++的指針到成員功能不能與C++引用使用,因爲我已經在本週早些時候獲悉:https://stackoverflow.com/a/8336479/1074536,所以我不能夠使用&美孚::例如refToAndInt。

至於我如何計算成員的偏移量,我沒有使用宏的偏移量,因爲我的類不總是POD。

因此,既然我不能使用指針到成員計算引用的偏移量,我想我會嘗試:

&(((Foo*)nullptr)->refToAnInt) 

但它已經指出了另一個堆棧溢出線程,這是未定義的行爲,顯然在LLVM上它崩潰。 :(

我想避免這樣做的東西一樣回吐此前成員的偏移,增加它的大小,然後以某種方式計算對準我的下一個成員所需的填充物,因爲它會顯得雜亂,而且容易出錯

所以,我不能什麼我可以嘗試下從我的其他可怕的建議,同時使用這些技巧和offsetof僅供豆莢。任何建議,除了?

謝謝!

+2

爲什麼要序列化/反序列化引用?它們必須在構造函數中初始化,並且無論如何都不能在以後更改。 –

+0

@ 7vies:如果你將一個對象看作一個簡單的字節數組,就很容易將引用視爲8個字節的塊(在64位上)來填充。這裏的想法是簡單地分配一個足夠大的字節數組來保存內存中的對象,然後使用類描述符打入值。我不處理vtables,所以我不需要構造函數來初始化。顯然,您必須確保在常規施工過程中沒有副作用,因此加載資產會使系統處於與保持之前相同的狀態。 – fronsacqc

+0

,因爲你已經有了不支持vtables的限制,我會說只是不支持引用 - 這對於不支持vtables是一種小小的限制。順便說一下,你將如何反序列化指針或引用? (顯然,你不能只將它們恢復到序列化時的相同值,因爲內存位置可能不同) –

回答

0

根據標準,

  1. 6 ... 甲平凡類是具有一個平凡缺省構造(12.1)和... 一類...

    10.一種POD結構是一類既是一個簡單的類... ...

12.1構造

5 ...

A default default constructor for class X is defined as deleted if: 

... 

- any non-static data member with no brace-or-equal-initializer is of 

引用類型,

... 

A default constructor is trivial if it is neither user-provided nor deleted 

並且如果其

... 

- for all the non-static data members of its class that are of class type(or 

陣列),每個這樣的類都有一個平凡缺省構造。

可以肯定,具有參考成員,除非大括號或相等的初始化程序存在,例如不能POD任何類:

class A 
{ 
    A &me=*this; 
}; 

如果是這樣的話,你可以創建特定的解決方法。

對於您可以嘗試以下的

&(((Foo*)nullptr)->refToAnInt) 

問題:

std::aligned_storage<sizeof(Foo), std::alignment_of<Foo>::value>::type storage; 
&((static_cast<Foo *>(static_cast<void *>(&storage)))->refToAnInt); 

其行爲應當加以明確界定。

+0

是的,我開始認爲用std :: aligned_storage分配一堆字節是解決這個問題的唯一方法。這很不幸,因爲我將不得不讓我的API有點髒。也許我也可以跳過對引用的支持。 ;) – fronsacqc