2014-12-30 10 views
7

Cả gcc 5.0 và kêu vang 3.6 đòi hỏi từ khóa typename trong ví dụ sau:Biểu thức ném hoặc xóa có bao giờ phụ thuộc không?

template<typename T> 
struct B 
{ 
    typedef int Type; 
}; 

template<int n> 
struct A 
{ 
    typedef typename B<decltype(throw (int*)n)>::Type Throw; 
    typedef typename B<decltype(delete (int*)n)>::Type Delete; 
}; 

này được bao phủ bởi các từ ngữ sau đây trong các tiêu chuẩn C++ 11:

[trừ]/2

Biểu thức ném có loại void.

[expr.delete]/1

Các toán hạng phải có một con trỏ đến kiểu đối tượng, hoặc một loại lớp có một đĩa đơn không rõ ràng chuyển đổi chức năng để một con trỏ đến kiểu đối tượng. Kết quả có loại void.

Vì vậy, tôi giả sử decltype sản xuất void trong cả hai trường hợp.

[expr.const]/2

Một điều kiện thể hiện là một biểu thức hằng lõi trừ khi nó liên quan đến một trong các cách sau như một subexpression khả năng đánh giá

  • mới thể hiện

  • một biểu thức ném

Điều này cho thấy rằng một biểu thức liên quan đến throw hoặc delete không được là cụm từ không đổi.

[temp.dep.type]/8

Một loại phụ thuộc nếu nó là

  • một đơn giản-template-id trong đó một trong hai tên mẫu là một tham số mẫu hoặc bất kỳ mẫu đối số nào trong số các đối số là một loại phụ thuộc hoặc một biểu thức phụ thuộc vào loại hoặc phụ thuộc vào giá trị

  • ký hiệu là decltype(expression), trong đó biểu thức là loại phụ thuộc nt

Vì vậy B<decltype(..)> phụ thuộc chỉ nếu biểu thức là gõ phụ thuộc.

[temp.dep.expr]/4

Expressions trong các hình thức sau đây không bao giờ gõ phụ thuộc (vì kiểu của biểu thức không thể phụ thuộc):

delete cast-expression 
throw assignment-expression 

Điều này cho thấy rằng không phải biểu hiện có thể được loại phụ thuộc vào .

Gcc và clang có sai không?

+0

Tôi không nghĩ lý do của bạn về [temp.dep.constexpr]/p1 là chính xác. Một 'reinterpret_cast' không thể xuất hiện trong một biểu thức liên tục, nhưng [temp.dep.constexpr]/p3 chỉ rõ rằng một biểu thức liên quan đến' reinterpret_cast' có thể có thể phụ thuộc vào giá trị. –

+0

'decltype (..)' không phải là một biểu thức. Vì vậy, bạn cũng cần [temp.dep.type] /9.8 Đoạn đó chỉ yêu cầu biểu thức trong 'decltype (expression)' không phải là * type-dependent *, được chỉ rõ cho 'throw' và' new'. – dyp

+0

@dyp Có! Điều đó dường như kết luận. – willj

Trả lời

7

Hãy quay lại khi yêu cầu typename. §14.6 [temp.res]/p3, tất cả dấu ngoặc kép là từ N4140:

Khi một có trình độ-id được thiết kế để chỉ một loại đó không phải là một thành viên của instantiation hiện tại (14.6.2.1) và số nested-name-specifier là loại phụ thuộc của nó, nó sẽ được bắt đầu bằng từ khóa typename, tạo thành một tên tệp-specifier.

Các có trình độ-id trong trường hợp này là B<decltype(throw (int*)n)>::Type (và phiên bản delete, mà việc phân tích là giống hệt nhau). Vì vậy, typename là bắt buộc nếu lồng nhau tên-specifier, hoặc B<decltype(throw (int*)n)>::, đề cập đến một loại phụ thuộc.

§14.6.2.1 [temp.dep.type]/p8 nói, với sáu viên đạn không liên quan bỏ qua, đó

Một loại phụ thuộc nếu nó là

[...]

(8.7) - một đơn giản-mẫu-id trong đó tên mẫu là thông số mẫu hoặc bất kỳ đối số mẫu nào là phụ thuộc loại hoặc biểu thức phụ thuộc vào loại hoặc phụ thuộc vào giá trị hoặc

(8,8) - được biểu thị bởi decltype(biểu), nơi biểu là gõ phụ thuộc (14.6.2.2).

B<decltype(throw (int*)n)>đơn giản-mẫu-id. Tên mẫu, B, không phải là thông số mẫu. Đối số mẫu duy nhất, decltype(throw (int*)n), không phải là một biểu thức, do đó, B<decltype(throw (int*)n)> chỉ phụ thuộc nếu decltype(throw (int*)n) là một loại phụ thuộc. decltype(throw (int*)n), lần lượt, mỗi viên đạn 8,8, chỉ phụ thuộc nếu throw (int*)n phụ thuộc vào loại. Nhưng chúng ta biết rằng, mỗi §14.6.2.2 [temp.dep.expr]/p4:

Expressions trong các hình thức sau đây không bao giờ gõ phụ thuộc (vì kiểu của biểu thức không thể phụ thuộc):

[...]

::optdeleteđúc biểu

[...]

thrownhượng thể hiện opt

[...]

Do đó, throw (int*)n không phải là loại phụ thuộc, và do đó decltype(throw (int*)n) không phải là một loại phụ thuộc, và do đó B<decltype(throw (int*)n)> không phải là một loại phụ thuộc, và do đó typename là không cần thiết cho B<decltype(throw (int*)n)>::Type, và do đó có, đây là một lỗi biên dịch.

+0

Hôm nay tôi cuối cùng đã nhận ra sai lầm của tôi là gì, và thấy nó được đề cập ngay trong câu trả lời của bạn. 'decltype (…)' không phải là một biểu thức. Tôi không bao giờ đặt câu hỏi này và bị kích thích bởi '[temp.dep.constexpr]/1'. :) – Columbo

Các vấn đề liên quan