2015-10-06 57 views
3

我一直在使用下面的模式將數據與任意對象綁定。每個T對象都位於Wrapper<T>中,附加數據可以從T的自己的地址獲得固定偏移量。通過投射第一個字段安全地訪問父類

template <class T> 
struct Wrapper 
{ 
    T core; 
    int id; 

    template <class ...Args> 
    Wrapper(int id, Args&&... args) 
     : id(id) 
     , core(std::forward<Args>(args)...) { } 
}; 

template <class T> 
Wrapper<T>& getWrapper(T& core) 
{ 
    return reinterpret_cast<Wrapper<T>&>(core); 
} 

void process(std::string& s) 
{ 
    std::cout << "'" << s << "' - id " 
     << getWrapper(s).id << "\n"; 
} 

int main() 
{ 
    auto *wrapper = new Wrapper<std::string>(188, "Costa Rica"); 

    process(wrapper->core); 
} 

如果我的標準的理解是正確的,這是便攜式提供T具有標準的佈局。

我的問題是GCC特定的。根據GCC對象模型,我能否假設這在T不是標準佈局時也可以使用?

回答

0

正如我確信你懷疑,答案是,你不能。 standard-layout classes的訣竅在於,他們可以安全地用reinterpret_cast轉換爲指向其第一個非靜態數據成員的指針並返回。您正在使用getWrapper()方法執行此操作。

當獲得虛擬成員或使用虛擬繼承時,標準佈局類變爲非標準。發生這種情況時,gcc將vtable指針置於零偏移位置,因此您不能再對reinterpret_cast執行第一個數據成員。

在您的實施中,您可能會考慮使用std::is_standard_layout來防止模式的不正確使用。

+0

即使T有一個vtable,爲什麼這會影響reinterpret_cast?重要的是Wrapper具有「標準」佈局(無Vtable),無論T佈局如何。請注意,我也假設T的地址與它的vtable指針一致。 –