2012-11-22 132 views
0

今天,我試圖對某個類是否具有嵌套類型reverse_iterator進行類型切換。我對這些論壇的一些工作的解決方案,這是下面的一個發現:嵌套成員類型識別

template<typename T> 
struct is_reverse_iterable 
{ 
    using yes = uint8_t; 
    using no = uint16_t; 

    template<typename U> 
    static yes& test(typename U::reverse_iterator*); 

    template<typename> 
    static no& test(...); 

    static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes); 
}; 

這個類,如果我只是從主檢查車況,工作得很好但是,我也寫了一點功能,這會導致一些問題。

template<typename T> 
void foo(T&& iter) 
{ 
    std::cout << typeid(T).name() << std::endl; 
    std::cout << is_reverse_iterable<T>::value << std::endl; 
} 

這裏是主要的引起了我一些問題:

int main() 
{ 
    using namespace std; 

    vector<int> v; 

    cout << typeid(decltype(v)).name() << endl; 
    cout << is_reverse_iterable<decltype(v)>::value << endl; 

    foo(v); 

    return 0; 
} 

由於std::vector<int>包含嵌套的類型名稱reverse_iterator,人們會認爲 - 或者至少,我認爲 - 這is_reverse_iterable<vector<int>>::value將返回true。無論我放在哪裏。但事實並非如此。這是上述的主要結果:

St6vectorIiSaIiEE 
1 
St6vectorIiSaIiEE 
0 

當從主調用,結構is_reverse_iterablevector<int>公認的名稱reverse_iterator,但它並沒有這樣做從01​​調用時。其實,我不知道爲什麼,我希望有人請向我解釋什麼問題是:)

P.S. :我使用MinGW g ++ 4.7.1編譯,使用-std = C++ 11選項。

+0

我不明白你的意思是「看來,代碼無法再找到嵌套類型的reverse_iterator,」......它沒有編譯?如果沒有,編譯錯誤是什麼?如果是的話,這句話意味着什麼,因爲編譯器可以找到編譯所需的一切...... – PlasmaHH

+0

我找到了問題並試圖解釋它發生的地方。對不起,以前不清楚:p – Morwenn

回答

1

的問題是,當你調用foo(v),可以推導出Tstd::vector<int>&類型(一個左參考),所以typename T::reverse_iterator將無法​​編譯。您可以輕鬆地檢查自己:

template<typename T> 
void foo(T&& iter) 
{ 
    std::cout << typeid(T).name() << std::endl; 
    std::cout << is_reverse_iterable<T>::value << std::endl; 

    typename T::reverse_iterator t; // <-- add this line to see what's wrong 
} 

產量:

3.cpp: In instantiation of ‘void foo(T&&) [with T = std::vector<int>&]’: 
3.cpp:40:10: required from here 
3.cpp:27:34: error: ‘std::vector<int>&’ is not a class, struct, or union type 

解決方案很簡單:刪除引用啓動SFINAE,例如前

static constexpr bool value = sizeof(test<typename std::decay<T>::type>(0)) 
           == sizeof(yes); 
+0

簡單而乾淨的答案,非常感謝。我不知何故想過在某處使用'remove_reference',但是你的答案更快。再次感謝! :) – Morwenn