2011-08-31 55 views
16

我merily新尾隨返回類型,我在那裏打了一個問題,這個(簡化)代碼的實驗尾隨返回類型,decltype和常量性

#include <list> 

class MyContainer{ 
    std::list<int> ints; 

    auto begin() -> decltype(ints.begin()) 
    { 
    return ints.begin(); 
    } 

    auto begin() const -> decltype(ints.begin()) 
    { 
    return ints.begin(); 
    } 
}; 

忽略的這段代碼是如何毫無意義的事實。最重要的部分是使用GCC 4.6.1時產生的編譯器錯誤(與-std=c++0x標誌):

In member function 'std::list<int>::iterator MyContainer::begin() const': 
error: could not convert '((const MyContainer*)this)->MyContainer::ints.std::list<_Tp, _Alloc>::begin [with _Tp = int, _Alloc = std::allocator<int>, std::list<_Tp, _Alloc>::const_iterator = std::_List_const_iterator<int>]()' from 'std::list<int>::const_iterator {aka std::_List_const_iterator<int>}' to 'std::list<int>::iterator {aka std::_List_iterator<int>}' 

如果你不涉及模板錯誤的風扇,短篇小說的是,在的身體const版本的MyContainer::begin,表達式ints.begin()返回類型std::list<int>::const_iterator的值(因爲ints在這種情況下爲const)。然而,當決定表達式的類型時,decltype(ints.begin())產生std::list<int>::iterator類型,即,decltype忽略const方法的限定符begin方法。毫不奇怪,類型的衝突是結果。

這對我來說似乎是GCC編譯器中的一個錯誤。只有decltype才能符合const限定符並生成const_iterator類型。任何人都可以證實或否認(甚至可以解釋)這個嗎?也許我在decltype的機制中忽略了一些東西,但是這看起來像一個非常簡單的場景。

注意:據我所知,相同的行爲不僅適用於std::list<int>,也適用於任何類型的成員函數重載的const-這些類型返回不兼容的類型。

+2

用gcc 4.7.0的最新快照編譯沒有錯誤。在這之前,我想你會陷入'ints.cbegin()' – Cubbi

+0

當然,在這樣一個微不足道的情況下,這並不是一個嚴重的障礙,但對於gcc來說,爲所有非平凡的案例也想確保*我*是正確的 - 我不想使用我不明白的功能)。 –

回答

10

你是對的,這是一個錯誤。據N3291,第5.1.1節,第3段:

如果聲明聲明一個類X的成員函數或成員函數模板,表達這是類型的指針」,以CV-合格音響ER-SEQ一個prvalue X「在可選的cv-qualifer-seq和函數定義,成員聲明符或聲明符的結尾之間。它不應出現在可選的cv-quali fi er-seq之前,它不應出現在靜態成員函數的聲明中(儘管它的類型和值類別是在靜態成員函數內定義的,因爲它們在非靜態成員函數內) 。 [注意:這是因爲聲明匹配在知道完整聲明之前不會發生。 -end note]與其他上下文中的對象表達式不同,*不需要成員函數體外的類成員訪問(5.2.5)的完整類型。 [注意:只有在聲明之前聲明的類成員纔可見。 - 注意]

但是這是最近一次工作草案和N3291之間的最近變化。所以海灣合作委員會恰好不到6個月前;這就是將代碼寫入移動規範的危險。

+0

這是我的想法的一部分,因爲我記得關於最後一份草案的一些討論,並在尾部返回類型中使用了'this',但我不確定那裏的任何提案是否真的被接受。謝謝你的參考答案。值得慶幸的是(根據Cubby的評論),GCC似乎已經在此之上,因爲4.7版已經解決了這個問題。 –