1

我想實現一個條件指針解引用函數。其基本思路是:C++函數模板專業化的行爲與右值引用

return is_pointer(arg) ? *arg : arg 

爲了限制需要專業化的數量,我試圖用右值引用了其中arg不是指針的情況。這是我目前的實現(std::cout在那裏僅用於調試目的):

template< typename T > 
inline typename std::enable_if< std::is_pointer<T>::value == false, T >::type deref(T&& t) 
{ 
    std::cout << std::is_pointer<T>::value << std::endl; 
    std::cout << typeid (T).name() << std::endl; 
    return t; 
} 

template< typename T > 
inline typename std::enable_if< std::is_pointer<T>::value == true, typename std::remove_pointer<T>::type& >::type deref(T t) 
{ 
    std::cout << std::is_pointer<T>::value << std::endl; 
    std::cout << typeid (T).name() << std::endl; 
    return *t; 
} 

現在,我得到GCC 4.6下一個相當奇怪的行爲。第一個重載用於非指針類型和指針類型。顯然,使用指針類型時,它與第二次重載衝突。如果我註釋掉第二個和呼叫使用的第一個下面...

int q; 
int *p = &q; 
deref(p); 

...對應的控制檯輸出爲:

0 
Pi 

這怎麼可能是一個非指針類型(根據std::is_pointer)也是指針類型(根據typeid)在相同的上下文中?由於std::is_pointer錯誤地將p錯誤地報告爲非指針類型,所以兩個過載之間出現衝突。此外,當我更換的第一個重載標準參考R值參考:

inline typename std::enable_if< std::is_pointer<T>::value == false, T >::type deref(T& t) 

它不與第二過載了衝突......我只是不明白這是怎麼回事。順便說一句,使用第二次超載收益(如預期):

1 
Pi 

感謝您的幫助。

回答

3

據我瞭解

template <T> 
void foo(T&&) 

意味着如果T是一個左值,它會被推斷爲(你的情況T = int*&)的參考和借鑑倒塌的int*&&&後產生有規律的左值參考int*&。如果不是這樣的話,這個語法會捕獲任何東西作爲右值引用。而重點是將左值與左值引用和右值綁定爲左值引用。

is_pointer<int*&>不正確。因此你可以嘗試申請remove_reference<T>

+0

感謝您的深入解釋。當我在enable_if條件中使用remove_reference時,它的確編譯。我不完全明白你的意思: – pmjobin 2011-02-11 21:13:31

2

在第一次重載時,T被推導爲int * &。嘗試在第一次重載時在enable_if-testing和output中使用remove_reference<T>::type