2016-05-14 39 views
7

這個最小的程序lambda表達式,本地類型和全局命名空間

template <typename X> 
void foo (X x) 
{ 
    bar (x); 
} 

template <typename X> 
void bar (X x) 
{ 
} 

int main() 
{ 
    foo ([]{}); 
} 

與海灣合作委員會(4.8.5和5.3)編譯和失敗,鐺編譯(3.7)

我的分析如下。

bar用於foo並在foo後聲明,因此它在foo定義點處不可見。 bar的唯一方法可以在foo找到,實例化點是通過參數相關的查找。

foobar的唯一參數是在main中定義的lambda。

顯然,gcc將它的類型視爲在全局命名空間中聲明的類型,而clang不是。因此,gcc可以通過ADL找到bar,並且clang不能。

int main() 
{ 
    struct K{}; 
    foo (K());  // gcc compiles, clang complains 
} 

它看起來像海灣合作委員會是在錯誤的位置:當我們使用main本地定義的類型

同樣的事情發生。根據標準的lambda類型是未命名的(expr.prim.lambda/3),所以它不應該屬於任何名稱空間。本地類型應該不屬於全局命名空間。

分析是否正確?這是一個已知的gcc錯誤嗎?

這個問題的靈感來自this question

+0

所以,簡短版本是「本地lambda的類型是否屬於一個命名空間,如果是的話,哪一個呢?」第二個含義是「文件/命名空間/類作用域的lambda類型是否屬於命名空間,如果是,哪一個?」 – Yakk

回答

7

GCC是正確的,每分辨率爲DR1690/1691

[expr.prim.lambda]/4

閉合類型在最小的塊範圍,類範圍,即包含相應λ-表達 或命名空間範圍中聲明。 [注意:這確定了與關閉類型([basic.lookup.argdep])相關聯的命名空間和類 的集合。 a lambda聲明符的參數類型不影響這些關聯的命名空間和 類。 - 注完]

[basic.lookup.argdep]/2

如果T是一個類類型(包括工會),其相關聯的類別是: 類本身;它是其成員的類別(如果有的話);和它的 直接和間接基類。其關聯的名稱空間是其相關類的最內層封閉名稱空間。

問題中的閉包類型的最內層封閉名稱空間是全局名稱空間,所以全局名稱空間是一個關聯的名稱空間。

+1

嗯,這看起來像在C++ 14中的新措辭。我的C++ 11草案副本說*其相關的命名空間是它的關聯類是其成員的命名空間*兩種編譯器都給出了與-std = C++ 11和-std = C++ 14相同的結果。 –

+1

@ n.m。啊,是的,http://wg21.link/cwg1690 –

2

GCC在這裏是錯誤的。它通過ADL發現bar(),儘管[]{}不是全局命名空間的成員。使用相同的引用T.C.使用:

[expr.prim.lambda]/4

閉合類型在最小的塊範圍,類範圍,即包含相應λ-表達 或命名空間範圍中聲明。 [注意:這確定了與關閉類型([basic.lookup.argdep])相關聯的命名空間和類 的集合。 a lambda聲明符的參數類型不影響這些關聯的命名空間和 類。 - 尾註]

通過故意引入錯誤很容易看出這一點。在GCC:

auto f = -[]{}; 

int main() 
{ 
    foo (f); 
} 

error: no match for 'operator-' (operand type is '<lambda()>') 

int main() 
{ 
    foo (-[]{}); 
} 

no match for 'operator-' (operand type is 'main()::<lambda()>') 

在另一方面,如果我們移動拉姆達聲明全球範圍內,鏘不抱怨:

auto f = []{}; 

int main() 
{ 
    foo (f); 
} 

FWIW這個報告爲Bug 57433爲GCC但它是未經證實的。它包含更多GCC接受/ Clang拒絕的程序示例。

+0

你有沒有讀過TC的答案中的第二個標準報價? –