2013-11-26 62 views
1

雖然想在這裏回答一個問題,我發現這個問題:遞歸取消引用指針

How to recursively dereference pointer (C++03)?

從答案

改編代碼如下:

template<typename T> T& dereference(T &v) { return v; } 

template<typename T> const T& dereference(const T &v) { return v; } 


template <typename T> 
typename std::enable_if<!std::is_pointer<T>::value, T&>::type 
dereference(T *v) { 
    return dereference(*v); 
} 

然而,在這個測試中它是無法將指針指針解除引用爲值類型:

template <typename T> 
class A 
{ 
public: 
     bool compare(T a, T b){ 
       return dereference(a) < dereference(b); 
     } 


}; 

int main() 
{ 

     int u = 10; 
     int *v = &u; 
     int **w = &v; 

     int i = 5; 
     int *j = &i; 
     int **k = &j; 

     A<int> a; 
     A<int*> b; 
     A<int**> c; 


     std::cout << a.compare(i, u) << std::endl; 
     std::cout << b.compare(j, v) << std::endl; 


     // This fails - 5 < 10 == 0 
     std::cout << **k << " < " << **w << " == " << c.compare(k, w) << std::endl; 


     return 0; 

} 

顯然,wk只被解除一次,這導致在兩個指針上調用operator<

我可以通過添加以下解決此問題:

template <typename T> 
typename std::enable_if<!std::is_pointer<T>::value, T&>::type 
dereference(T **v) { 
    return dereference(*v); 
} 

但隨後會失敗int***

有什麼辦法可以遞歸地做到這一點,而無需手動添加級別?

注意這只是「理論上」的問題。

回答

5

這是可能與使用定製can_dereference性狀:

template <typename T> 
struct can_dereference_helper { 
    template <typename U, typename = decltype(*std::declval<U>())> 
    static std::true_type test(U); 
    template <typename...U> 
    static std::false_type test(U...); 
    using type = decltype(test(std::declval<T>())); 
}; 

template <typename T> 
struct can_dereference : 
    can_dereference_helper<typename std::decay<T>::type>::type {}; 

,並用bit'o標籤調度一些相互遞歸函數:

template <typename T> 
auto recursive_dereference(T&& t, std::false_type) -> 
    decltype(std::forward<T>(t)) { 
    return std::forward<T>(t); 
} 

template <typename T> 
auto recursive_dereference(T&& t) -> 
    decltype(recursive_dereference(std::forward<T>(t), can_dereference<T>{})); 

template <typename T> 
auto recursive_dereference(T&& t, std::true_type) -> 
    decltype(recursive_dereference(*std::forward<T>(t))) { 
    return recursive_dereference(*std::forward<T>(t)); 
} 

template <typename T> 
auto recursive_dereference(T&& t) -> 
    decltype(recursive_dereference(std::forward<T>(t), can_dereference<T>{})) { 
    return recursive_dereference(std::forward<T>(t), can_dereference<T>{}); 
} 

See it work live at Coliru.這似乎是大材小用相比Kerrek的答案,但我去了一個通用的方法,將解引用任何支持operator*。我會讓你決定哪種工具最適合你的問題。

+0

謝謝!我希望我能接受這兩個答案,因爲我知道你們都在這方面投入了時間! –

+0

這可能比我的回答好得多,因爲我的CV不符合各種資歷。 –

2

您可以用特徵來計算最終的返回類型做到這一點,這裏被稱爲remove_all_pointers

#include <type_traits> 

template <typename T> struct remove_all_pointers 
{ typedef typename std::remove_reference<T>::type type; }; 
template <typename T> struct remove_all_pointers<T *> 
{ typedef typename std::remove_reference<T>::type type; }; 

template <typename T> 
T & dereference(T & p) 
{ return p; } 

template <typename U> 
typename remove_all_pointers<U>::type & dereference(U * p) 
{ return dereference(*p); } 

int main(int argc, char * argv[]) 
{ 
    return dereference(argv); 
} 

您可能需要添加CV-變種;我仍然在想那個。

+1

我想你需要遞歸地應用'remove_all_pointers',你知道,刪除所有的指針。 – Casey

+0

即[如此](http://coliru.stacked-crooked.com/a/03b09343fa28fac5)。 – Casey

+0

謝謝!我希望我能接受這兩個答案,因爲我知道你們都在這方面投入了時間! –