13

Tôi đang viết một số mã TMP-nặng cho g ++ (phiên bản 4.8.1_1, Macports) và clang ++ (phiên bản 3.3, Macports). Mặc dù g ++ từ chối danh sách mã sau bằng UNBRIDLED FURY, clang ++ biên dịch với ân huệsplendor.g ++ Bug với một phần mẫu chuyên môn

  • Trình duyệt nào ở bên phải? (Tôi mạnh mẽ nghi ngờ đó là g ++, nhưng tôi muốn nhận được sự bảo đảm từ những người khác trước khi gửi báo cáo lỗi.)
  • Bạn có cách giải quyết dễ dàng hoặc thanh lịch nào không? (Tôi cần phải sử dụng mẫu bí danh, vì vậy chuyển đổi sang cấu trúc, gây g ++ để chấp nhận các mã, không phải là một lựa chọn.)

Dưới đây là danh sách mã, làm chỉ dành riêng cho bạn.

template <class... Ts> 
struct sequence; 

template <int T> 
struct integer; 

// This definition of `extents` causes g++ to issue a compile-time error. 
template <int... Ts> 
using extents = sequence<integer<Ts>...>; 

// However, this definition works without any problems. 
// template <int... Ts> 
// struct extents; 

template <int A, int B, class Current> 
struct foo; 

template <int A, int B, int... Ts> 
struct foo<A, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

template <int B, int... Ts> 
struct foo<B, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

int main() 
{ 
    using t = foo<1, 1, extents<>>::type; 
    return 0; 
} 

Đây là g ++ 's đầu ra:

er.cpp: In function 'int main()': 
er.cpp:39:41: error: ambiguous class template instantiation for 'struct foo<1, 1, sequence<> >' 
    using t = typename foo<1, 1, extents<>>::type; 
             ^
er.cpp:26:8: error: candidates are: struct foo<A, B, sequence<integer<Ts>...> > 
struct foo<A, B, extents<Ts...>> 
     ^
er.cpp:32:8: error:     struct foo<B, B, sequence<integer<Ts>...> > 
struct foo<B, B, extents<Ts...>> 
     ^
er.cpp:39:43: error: 'type' in 'struct foo<1, 1, sequence<> >' does not name a type 
    using t = typename foo<1, 1, extents<>>::type; 
             ^

Đây là kêu vang ++' s đầu ra:

Nhờ sự giúp đỡ của bạn!

+4

'+ 1' chỉ để đùa thôi :) Tôi cũng cá là Clang ở ngay đây. –

+0

'typename' trong' main' là không cần thiết –

+0

@ DavidRodríguez-dribeas Cảm ơn, nó trở thành một thói quen ... –

Trả lời

7

Điều này có vẻ giống như lỗi g ++ vì rõ ràng foo<B, B, extents> là chuyên biệt hơn foo<A, B, extents> (sau này có thể khớp với bất kỳ thứ gì khớp với trước đây, nhưng không ngược lại), do đó trình biên dịch nên chọn chuyên môn đó.

Như bạn đã lưu ý, thay đổi extents từ bí danh mẫu thành mẫu lớp, giải quyết sự cố.

3

Câu hỏi đặt ra sôi xuống nếu tôi hiểu nó một cách chính xác để xác định liệu một trong những mẫu chuyên ngành sau đây là chuyên biệt hơn so với khác:

template <int A, int B, class Current> 
struct foo; 

template <int A, int B, int... Ts> 
struct foo<A, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

template <int B, int... Ts> 
struct foo<B, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

Và câu trả lời là , đối với bất kỳ sự kết hợp của các thông số đó được cho phép trong chuyên môn thứ hai cùng một sự kết hợp được cho phép trong lần đầu tiên bằng cách tạo các đối số mẫu A == B. Theo hướng khác, bất kỳ phiên bản nào của chuyên môn mẫu đầu tiên mà trên đó A != B không thể là đối sánh cho chuyên môn thứ hai, do đó, thứ hai đúng là chuyên biệt hơn so với lần đầu tiên.

0

Tôi tin rằng g + + có thể đúng. Dòng

using t = foo<1, 1, extents<>>::type 

đang sử dụng các thông số mẫu trong một bối cảnh không suy luận, vì vậy nó không thể sử dụng các giá trị thực tế đưa ra cho các thông số mẫu để giải quyết sự mơ hồ, chỉ có loại của họ và đó không phải là đủ.

mục 14.8.2.5, para 4 của chuẩn C++ nói:

Trong hầu hết trường hợp, giá trị các loại, mẫu, và không loại được sử dụng để soạn P tham gia vào khấu trừ mẫu tranh cãi. Tức là, chúng có thể được sử dụng để xác định giá trị của một đối số mẫu và giá trị được xác định phải phù hợp với các giá trị được xác định ở nơi khác.Tuy nhiên, trong một số ngữ cảnh nhất định, giá trị không tham gia vào loại khấu trừ, mà thay vào đó sử dụng các giá trị của đối số mẫu mà được suy luận ở nơi khác hoặc được chỉ định rõ ràng. Nếu tham số mẫu chỉ được sử dụng trong các ngữ cảnh không được suy luận và không được chỉ định rõ ràng, thì việc trích lập đối số mẫu không thành công.

Các bối cảnh phi suy luận là:

x Các lồng nhau-tên-specifier của một loại mà đã được chỉ định sử dụng một trình độ-id

...

Mục 14.8.2.4 đoạn 11 nói:

Trong hầu hết các trường hợp, tất cả thông số mẫu phải có giá trị để khấu trừ thành công, nhưng cho mục đích đặt hàng một phần thông số tấm có thể vẫn không có giá trị miễn là nó không được sử dụng trong các loại đang được sử dụng để đặt một phần. [Lưu ý: Thông số mẫu được sử dụng trong ngữ cảnh không được suy luận được xem là đã sử dụng. —end note]

Vì vậy, chúng tôi đang ở trong một ngữ cảnh không được suy luận, có nghĩa là tất cả các đối số mẫu phải có giá trị. Vì vậy, nếu extents <> không móng tay xuống loại, sau đó kết quả sẽ được mơ hồ theo tiêu chuẩn. Có hợp lý không?

+0

Các biểu thức "P" là 'A',' B', 'extents '. Các biểu thức "A" là '1',' 1', 'extents <>'. Không có biểu thức "P" nào sử dụng bất kỳ tham số mẫu nào trong một ngữ cảnh không được suy luận. – aschepler

+0

Không phải là loại :: ở cuối làm cho nó một id đủ điều kiện? –

+0

Có, 'foo <1, 1, extents <>> :: type' là một id đủ điều kiện. Nhưng nó không sử dụng bất kỳ tham số mẫu nào. Nó chứa một số đối số mẫu ("A" trong 14.8.2). Các đối số trong id đủ điều kiện được so sánh để khấu trừ; chúng không được suy luận. – aschepler

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