2013-02-25 67 views
10

我想驗證以下是GCC中的錯誤,而不是我對C++的理解。考慮下面的代碼:驗證GCC中的錯誤

struct A 
{ 
    struct B 
    { 
     template< typename U > U as() const { return U(); } 
    }; 

    B operator[](int) const { return B(); } 
}; 

template< typename T > 
struct as 
{ 
    template< typename U > 
    static T call(const U& u) 
    { 
     return u[ 0 ].as<T>(); // accepted by Clang 3.2, rejected by GCC 4.7 
     // return u[ 0 ].template as<T>(); // does not help and is IMHO not needed 
     // return u[ 0 ].A::B::as<T>(); // accepted by GCC 4.7 
    } 
}; 

int main() 
{ 
    as<int>::call(A()); 
} 

IMHO代碼要細,它是由鐺3.2接受,但不是由GCC 4.7(4.4和4.6也失敗,基本上是相同的錯誤,但4.4產生稍微不同的消息) 。下面是從我的殼輸出:

$ clang++-3.2 -O3 -Wall -Wextra -std=c++0x t.cc -o t 
$ g++-4.7 -O3 -Wall -Wextra -std=c++0x t.cc -o t 
t.cc: In static member function ‘static T as<T>::call(const U&)’: 
t.cc:17:21: error: invalid use of ‘struct as<T>’ 
t.cc: In static member function ‘static T as<T>::call(const U&) [with U = A; T = int]’: 
t.cc:18:4: warning: control reaches end of non-void function [-Wreturn-type] 
$ 

問:這是海灣合作委員會中的一個bug還是我失去了一些東西?

編輯:我有點困惑:在http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576的GCC錯誤報告在評論#9中說,評論#3中的代碼是「有效的」。這到底是什麼意思?它看起來像海灣合作委員會的人認爲它實際上一個錯誤,否則他們會已經關閉它? OTOH @Potatoswatter的答案似乎很清楚,它應該是正確的,我應該提交一份針對叮鐺的錯誤報告(或者是否已經有這樣的錯誤報告?)

請注意,我毫不猶豫地將答案標記爲接受直到上述內容被澄清。既然這兩個答案都已經有幫助(一個解釋,一個解決方法),我同時給出了兩個答案。

獎金問題:由於我得到了非敘述性代碼的低估,我想知道別人的感受。我試圖創建一個SCCEE,它消除了所有的干擾並專注於技術問題。這就是我更喜歡考慮這些事情的方式。那是錯的嗎?

另外,@EdHeal:爲什麼代碼容易發生災難? (你不認爲這是我真實世界的代碼,對嗎?)

EDIT2:謝謝大衛,剛剛注意到你的編輯。我會將您的答案標記爲已接受,並且我還看到您對GCC錯誤報告發表了評論。我認爲這個問題的主要意見從而得到了答覆,海灣合作委員會得到了另一個提醒。感謝大家。

+0

我相信這是一個已知的錯誤。 – Potatoswatter 2013-02-25 10:20:48

+4

但是,由於'u [0]'是一個依賴表達式,所以'template'關鍵字是必需的。解析器需要能夠在不知道'U'的情況下找出'<'符號的含義,並且不需要查找'>'。 – Potatoswatter 2013-02-25 10:23:23

+0

這就是我所想的,Clang應該拒絕這些代碼。 – Xeo 2013-02-25 10:25:13

回答

5

這是對一個棘手的角落語言。 GCC被施加從C++ 03§3.4.5/ 1的規則:

在一類成員訪問表達式(5.2.5)中,如果.->令牌之後緊接着一個標識符後跟一個<,必須查找標識符以確定<是模板參數列表(14.2)的開始還是小於運算符。標識符首先在對象表達式的類中查找。如果找不到標識符,則在整個後綴表達式的上下文中查找它,並命名類或函數模板。如果對象表達式的類中的查找查找到模板,則在整個後綴表達式的上下文中查找該名稱,並且如果找不到該名稱,則在整個後綴表達式的類中找到該名稱對象表達被使用,否則

- 如果名稱在整個後綴表達式的上下文中發現,沒有指定類模板,在該對象的類別的表達的發現名稱被使用,否則

- 如果找到的名稱是類模板,則它必須引用與在對象表達式的類中找到的實體相同的實體,否則該程序是格式不正確的。

注意,因爲template關鍵字已經被要求澄清對<令牌,因爲子表達式u[0]的類型依賴於一個模板參數這一過程是無用的。

這樣做的原因是在template-id用於嵌套名稱限定符的情況下簡化解析,例如u[ 0 ].as<T>::bar.baz其中bar是對基類的typedef。

C++ 11刪除三個要點簡化了工藝,以

標識符首先在該對象的類別的表達擡頭。如果找不到標識符,則在整個後綴表達式的上下文中查找它,並命名一個類模板。

所以這是一個錯誤,而不是我之前說過的那個舊的錯誤。名稱查找角落案件需要被刪除。

此外,它看起來像這個怪癖可以被利用來允許單個模板表達式交替引用類或函數。不確定這是否有用,但它在C++ 11中是新的。

+0

等一下,所以全局'as'的名字實際上是爲嵌套表達式找到的?笏。 – Xeo 2013-02-25 11:50:49

+0

@Xeo Yep,只是因爲他們想在最後一段作品中使我的設計變得像我的設計一樣。 – Potatoswatter 2013-02-25 11:52:06

+0

這是來自公佈的標準嗎?我在n3337或n3485中看不到這些子彈。 – ecatmur 2013-02-25 11:53:41

1

問題在於as作爲類和模板名都被注入template<...> struct as的範圍;這就是爲什麼gcc抱怨「invalid use of ‘struct as<T>’」。

我不太清楚GCC是否正確(它的下跌,爲會員表情名字查找規則),但解決方法是使用decltype

return u[ 0 ].decltype(u[ 0 ])::template as<T>(); 
+0

注入名稱不可能在那裏有效,因爲它是一個無關的嵌套名稱類。 – Xeo 2013-02-25 11:43:29

+0

@Xeo我不確定你的意思是「有效」。編譯器不知道'U'是不相關的,它也不知道它具有'as'成員模板。 – ecatmur 2013-02-25 11:57:05