2017-10-01 104 views
0
struct A 
{ 
}; 
struct B : A 
{ 
    virtual ~B() {} 
}; 
template<typename BASE, typename EXTENDED> 
void ASSERT_BASE_EXTENDED() 
{ 
    static_assert(static_cast<BASE*>((EXTENDED*)256)==(BASE*)256, "error"); 
} 

我正在尋找一種方式來有一個編譯時斷言檢查,如果基類的延伸的基礎,他們有相同的內存地址。C++編譯時斷言,BASE是基類的延伸,具有相同的內存地址

在上面的例子中,即使B是基於A的,當被轉換爲A時它具有不同的存儲器地址,因爲虛擬函數表指針實際上是B的第一個成員。但是我需要檢查如果A是第一名成員。

上述工作正常,但不是編譯時,因爲我得到一個錯誤:使用VS 2017年編譯器時,「錯誤C2131表達式的結果不是一個常量」。

我不感興趣「的std :: is_base_of」,因爲這一個忽略檢查相同的內存地址。 有沒有另一種方法來做到這一點?

謝謝

+0

你想使用[_CRTP_(https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)和'static_cast'? – user0042

+0

CRTP是一個有趣的概念,但目標是不要修改現有的類,只調整ASSERT_BASE_EXTENDED函數。 – Esenthel

回答

1

內存地址是一個運行時構造。你不能在編譯時檢查它們,因爲那時它們不存在。你提到的那種鑄造也是如此。完全在運行時發生。您必須使用運行時檢查和錯誤處理來替換static_assert,例如一個assert()或一個例外。

這對國際海事組織共同使用的情況。對於你的例子中的硬編碼內存地址,問題是這些地址插入指針。要做到這一點的唯一有效的辦法就是reinterpret_cast的(這是編譯器試圖爲C樣式轉換在你的榜樣鑄件中的一個),因爲該類型INT指針到T完全無關。但是reinterpret_cast在編譯時是不允許的。

鏘的錯誤消息所言很好:

main.cpp:14:38: note: cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression 
    static_assert(static_cast<BASE*>((EXTENDED*)256)==(BASE*)256, "error"); 
            ^
+0

我不同意你的看法。如果你再次檢查我的代碼,你會看到我正在創建一個指向一個256的常量內存地址的對象。另外我使用了static_cast,它與dynamic_cast不同,它可以通過已知的編譯器值對內存偏移進行調整。沒有什麼能夠阻止編譯器在編譯時評估整個行,但它不會。這些基本上是在編譯時對已知常量的算術運算。 – Esenthel

+0

我憑直覺將這些硬編碼地址用於簡化問題。對於這種情況,實際問題是演員。查看更新後的答案。 – besc

+0

IMO無論編譯器能夠優化(預先計算) - 他們應該。如果他們願意,那麼它會解決我的問題。 – Esenthel