2015-11-14 16 views
3

我正在計劃最近這是這樣的: -檢查使用常量性type_traits

#include <iostream> 
#include <memory> 
#include <type_traits> 
#include <typeinfo> 
using namespace std; 

int main() 
{ 
    shared_ptr<int> sp1 = make_shared<int>(5); 
    shared_ptr<const int> sp2 (sp1); 
    const int x = 8; 

    // *sp2 = 7; // error: assignment of read-only location 'sp2.std::shared_ptr<const int>::<anonymous>.std::__shared_ptr<_Tp, _Lp>::operator*<const int, (__gnu_cxx::_Lock_policy)2u>()' 

    auto p = sp2.get(); 

    cout << typeid(x).name() << '\t' << typeid(*p).name() << '\n'; 

    cout << boolalpha; 
    cout << is_const<decltype(*p)>::value << '\n' << is_same<const int, decltype(*p)>::value; 

    return 0; 
} 

這個程序的輸出是: -

i i 
false 
false 

至於清晰可見,typeid規定*p & x是相同類型&即使使用*sp2 = 7也會產生錯誤。那爲什麼std::is_same & std::is_const有什麼不同呢?

回答

3

您在這裏遇到兩個不同的問題。第一種情況,我們可以從typeid的cppreference條目頂級常量限定符被忽略看到:

在所有情況下,CV-預選賽被typeid的忽略(即,typeid的(T)== typeid的(常量ŧ ))

我們可以從decltype的cppreference入口看到,下面的規則在這裏是有意義的:

  1. F中的參數是一個加括號的ID-表達或聯保會出現類的成員訪問,然後decltype將生成由此表達式命名的實體的類型。 [...]
  2. 如果參數是類型T的任何其他表達,和

[...]

  • 如果表達式的值類是左值,然後decltype產生Ť &;

[...]

所以*p是一個表達式,而不是一個ID表達也不像我們說下面的情況下,類成員訪問:

const int x = 0 ; 
std::cout << is_const<decltype(x)>::value << "\n" ; 
         ^^^^^^^^^^^ 

哪會由於x是一個id表達式,因此產生了真正的結果。

因此*p是一個表達式將產生T&,因爲結果是一個左值。基準本身不會是const所以is_const是正確的,在另一方面,這將返回你想要的結果:

is_const<std::remove_reference<decltype(*p)>::type>::value 
     ^^^^^^^^^^^^^^^^^^^^^ 

注意使用std::remove_reference

T.C.指出std::remove_pointer在這裏也可能有效:

is_const<std::remove_pointer<decltype(p)>::type>::value 
+0

nvm,混淆'p' /'sp'。雖然在這種情況下我會去'remove_pointer '(或者通過'pointer_traits :: element_type',雖然這可能是過度的 - 它確實有處理普通指針和智能指針的好處)。 –

+0

@ T.C。好吧,這很有道理,編輯回答 –

+0

很酷,謝謝! – Anwesha