2014-04-17 82 views
0

雖然試圖制定一個C宏來緩解非常量成員函數的寫作,調用具有完全相同邏輯的常量成員函數(請參見Effective C++的第1章第3項「避免常量和非常量成員函數中的重複」) ,我相信我在VS2013更新跨越decltype()錯誤傳來1.decltype(* this)VS2013中的錯誤?

我想用decltype(*this)在上述宏觀建立一個static_cast<decltype(*this) const&>(*this)表達,以避免在宏調用點傳遞任何明確的類型信息。但是,後一個表達式在某些情況下在VS2013中似乎沒有正確添加const。

這裏的一個很小的代碼塊,我能夠做回購的bug:

#include <stdio.h> 

template<typename DatumT> 
struct DynamicArray 
{ 
    DatumT* elements; 
    unsigned element_size; 
    int count; 

    inline const DatumT* operator [](int index) const 
    { 
     if (index < 0 || index >= count) 
      return nullptr; 

     return &elements[index]; 
    } 

    inline DatumT* operator [](int index) 
    { 
#if defined(MAKE_THIS_CODE_WORK) 
     DynamicArray const& _this = static_cast<decltype(*this) const&>(*this); 
     return const_cast<DatumT*>(_this[index]); 
#else 
     // warning C4717: 'DynamicArray<int>::operator[]' : recursive on all control paths, function will cause runtime stack overflow 
     return const_cast<DatumT*>(
       static_cast<decltype(*this) const>(*this) 
       [index] 
      ); 
#endif 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    DynamicArray<int> array = { new int[5], sizeof(int), 5 }; 
    printf_s("%d", *array[0]); 
    delete array.elements; 

    return 0; 
} 

(可以第一個亂說關於不使用的std :: vector的窟窿)

你可以編譯上面的代碼並自己看看警告,或者參考我的獨立評論來看看VC++會在你身上發生什麼。那麼你可以! defined(MAKE_THIS_CODE_WORK)表達式有VC++編譯代碼,因爲我除了#else代碼工作。

我在這臺機器上沒有可靠的clang設置,但我能夠使用GCC Explorer查看clang是否投訴(click to see/compile code)。它沒有。但是,g ++ 4.8會給你一個‘const’ qualifiers cannot be applied to ‘DynamicArray&’錯誤消息,使用相同的代碼。所以也許g ++也有bug?

談到decltype and auto標準紙(雖然,這幾乎是11歲),第6頁的最底部說decltype(*this)在非const成員函數應該是T&,所以我敢肯定這應該是合法的...

所以我錯誤的嘗試使用decltype()on * this加上const加入它?或者這是VS2013中的一個錯誤?顯然g ++ 4.8,但以不同的方式。

編輯:感謝Ben Voigt的迴應,我能夠弄清楚如何爲我想做的事情製作獨立的C宏。

// Cast [this] to a 'const this&' so that a const member function can be invoked 
// [ret_type] is the return type of the member function. Usually there's a const return type, so we need to cast it to non-const too. 
// [...] the code that represents the member function (or operator) call 
#define CAST_THIS_NONCONST_MEMBER_FUNC(ret_type, ...) \ 
    const_cast<ret_type>(        \ 
     static_cast<         \ 
      std::add_reference<       \ 
       std::add_const<       \ 
        std::remove_reference<    \ 
         decltype(*this)     \ 
        >::type        \ 
       >::type         \ 
      >::type          \ 
     >(*this)          \ 
     __VA_ARGS__          \ 
    ) 
// We can now implement that operator[] like so: 
return CAST_THIS_NONCONST_MEMBER_FUNC(DatumT*, [index]); 

最初的願望是隱藏這一切都在一個宏,這就是爲什麼我不想擔心創建的typedef或this別名。 GCC Explorer中的叮噹聲並沒有輸出警告,但仍然好奇,儘管輸出組件確實顯得有些魚腥味。

+0

我想我的問題可以被認爲是這一個的重複(雖然我沒有遇到它,而研究我最初的問題)http://stackoverflow.com/questions/7416251/using-decl類型轉換爲這個到const – kornman00

回答

5

你說你自己,decltype (*this)T&decltype (*this) const &試圖形成一個參考文獻(T& const &)。 decltype觸發參考摺疊規則8.3.2p6。但它不會以你想要的方式崩潰。

你可以說decltype(this) const&,但那將是T* const& - 對const指針的引用,而不是指向const對象的指針。出於同樣的原因,decltype (*this) constconst decltype (*this)不構成const T&,但(T&) const。關於引用的頂級const是無用的,因爲引用已經禁止重新綁定。

也許你正在尋找的東西更像

const typename remove_reference<decltype(*this)>::type & 

但注意添加const當你不需要投的。取而代之的

DynamicArray const& _this = static_cast<decltype(*this) const&>(*this); 

只是說

DynamicArray const& _this = *this; 

這些結合起來,

const typename std::remove_reference<decltype(*this)>::type & this_ = *this; 

不過,這是一個代碼,一個非常簡單的和普遍的問題愚蠢的量。只是說:

const auto& this_ = *this;


僅供參考這裏的參考文本崩潰規則:

如果的typedef名(7.1.3,14.1)或decltype-specifier(7.1.6.2)表示類型TR,它是對類型T的引用,嘗試創建類型「左值引用NCE到CVTR「創建類型‘左值參照T’,而試圖創建類型‘右值參照CVTR’創建類型TR

decltype(*this)是我們decltype說明符,其表示TR,這是DynamicArray<DatumT>&。這裏,TDynamicArray<DatumT>。嘗試TR const&是第一種情況,嘗試創建(const)TR的左值引用,因此最終結果爲T&,而不是const T&。簡歷資格不在最內層的參考文獻中。

+0

謝謝Ben!我用我試圖創建的C宏更新了我的問題,以便隱藏這個廢話,並避免使用typedef或「this」別名。我仍然很好奇爲什麼GCC Explorer中的鏗鏘聲沒有提出錯誤甚至是警告......當我回到家時,必須在適當的環境中嘗試它。 – kornman00

+0

@ kornman00:在我意識到可以使用'auto'之前,此答案的以前版本建議'template const T&deref_as_const(T * that){return * that; }'使用它來代替所有這些類型特徵垃圾。嘗試在存在隱式轉換時不要使用顯式轉換。如果你的演員出錯了,那麼你已經告訴編譯器閉嘴,按照它所說的去做。 –

+0

我在哪裏使用顯式演員?我可以發誓我在發佈的所有代碼中堅持static_cast(隱式)和const_cast(必需,因爲const成員函數返回一個const對象)。當我試圖避免向宏本身公開任何細節時,'de_ref_as_const'輔助函數也是好的 – kornman00

0

關於宏

// Cast [this] to a 'const this&' so that a const member function can be invoked 
// [ret_type] is the return type of the member function. Usually there's a const return type, so we need to cast it to non-const too. 
// [...] the code that represents the member function (or operator) call 
#define CAST_THIS_NONCONST_MEMBER_FUNC(ret_type, ...) \ 
    const_cast<ret_type>(        \ 
     static_cast<         \ 
      std::add_reference<       \ 
       std::add_const<       \ 
        std::remove_reference<    \ 
         decltype(*this)     \ 
        >::type        \ 
       >::type         \ 
      >::type          \ 
     >(*this)          \ 
     __VA_ARGS__          \ 
    ) 

這是更清潔做

// Cast [this] to a 'const this&' so that a const member function can be invoked 
template<typename T> const T& deref_as_const(T* that) { return *that; } 

// [ret_type] is the return type of the member function. Usually there's a const return type, so we need to cast it to non-const too. 
// [...] the code that represents the member function (or operator) call 
#define CAST_THIS_NONCONST_MEMBER_FUNC(ret_type, ...) \ 
    const_cast<ret_type>(deref_as_const(this)__VA_ARGS__) 

這是較短,自成體系,具有除__VA_ARGS__ C++ 98兼容,並避免不必要的投

+0

需要在宏中刪除「this」的取消引用,但否則會起作用。雖然,DEBUG構建會爲每個實例化類型的deref_as_const生成一個函數(更詳細的代碼密集宏不會),即使您聲明爲「inline」(至少在VC++中)。 – kornman00

+0

有兩個解除引用的好處。 –