2017-06-03 33 views
8

gcc 8.0.0clang 5.0.0 bất đồng về hành vi của chương trình này: Hành viđặt hàng một phần của tài liệu tham khảo chuyển tiếp và tham khảo bình thường với trích dẫn

#include <iostream> 

template <typename T> 
struct A { 
    A(const T&) { std::cout << __PRETTY_FUNCTION__ << '\n'; } 
    A(T&&)  { std::cout << __PRETTY_FUNCTION__ << '\n'; } 
}; 

template <typename U> A(U&&) -> A<double>; 

int main() { 
    int i = 0; 
    const int ci = 0; 

    A a1(0); // both say A<double> 
    A a2(i); // both say A<double> 
    A a3(ci); // gcc says A<int>, clang says A<double> 
} 

gcc của không có ý nghĩa với tôi - nếu tình trạng quá tải const T& được ưa chuộng hơn U&& quá tải cho lvalue const int, tại sao không phải là quá tải T&& được ưu tiên cho quá tải U&& cho rvalue int? clang của có ý nghĩa hơn với tôi (không có chức năng nào là chuyên môn hơn người khác, vì vậy hướng dẫn khấu trừ sẽ thắng).

Ai là đúng?

+0

Tôi sẽ thực hiện việc này. Khoản khấu trừ là cho một rvalue (tham khảo). 'ci' là một lvalue của' const', và có một constructor có tham chiếu đến 'const' như một tham số. –

+0

Xin lỗi vì thiếu hiểu biết của tôi, nhưng cú pháp '-> này được gọi là như thế nào? – HolyBlackCat

Trả lời

7

Chúng tôi đang ở lại một phần đất đặt hàng một lần nữa. Các loại các thông số chức năng mẫu tổng hợp là

T&&  // #1: not a forwarding reference 
const T& // #2 
U&&  // #3: a forwarding reference 

các pre-phần đặt hàng chuyển đổi strips away referenceness và sau đó các top-level cv-qualification, để lại cho chúng ta một loại trần trong cả ba trường hợp. Nó sau đó trong tất cả ba trường hợp khấu trừ thành công trong cả hai hướng. Hiện chúng tôi đang trái với [temp.deduct.partial]/9 của sợi giây:

Nếu vì một loại nhất định, khấu trừ thành công trong cả hai chiều (ví dụ, các loại giống hệt nhau sau khi biến đổi ở trên) và cả P ​​và A là loại tài liệu tham khảo (trước khi được thay thế bằng các loại gọi trên):

  • nếu loại từ mẫu đối số là một giá trị trái tài liệu tham khảo và các loại từ các mẫu tham số được không, loại tham số không được coi là ít nhất là chuyên ngành như loại đối số; nếu không,
  • nếu loại từ mẫu đối số có độ phân giải cao hơn loại từ mẫu tham số (như được mô tả ở trên), loại tham số không được coi là ít nhất .

Đối U&& vs T&&, không áp dụng quy tắc và không có trật tự. Tuy nhiên, đối với U&&const T&, loại tham số U&& không được coi là ít nhất là chuyên biệt làm loại đối số const T&, cho mỗi dấu đầu dòng.

Đặt hàng một phần do đó tìm thấy số 2 để chuyên biệt hơn # 3, nhưng thấy số 1 và số 3 không thể phân biệt được. GCC là chính xác.

Điều đó nói rằng, điều này cũng có thể là sự giám sát trong các quy tắc đặt hàng một phần. Khấu trừ mẫu lớp là lần đầu tiên chúng tôi có một "tham chiếu rvalue tham số mẫu cv-unqualified đó không phải là một tham chiếu chuyển tiếp" điều. Trước đây, trong trường hợp tham chiếu kép, tham chiếu chuyển tiếp sẽ luôn bị mất tham chiếu rvalue không chuyển tiếp ở dấu đầu dòng thứ hai (vì cách duy nhất bạn nhận được tham chiếu rvalue không chuyển tiếp là nếu bạn có cv T&& cho một số không rỗng cv).

+0

Tất cả đều có ý nghĩa. Theo đoạn cuối, bạn có nghĩ rằng dấu đầu tiên nên bao gồm cả tham chiếu rvalue không chuyển tiếp quá không (ví dụ: thích 'T &&' thành 'U &&')? – Barry

+0

Iirc, độ phân giải quá tải có các dấu ngắt kết nối liên quan đến cả việc đặt mua một phần và kiểm tra xem một trong hai ứng cử viên có phải là hướng dẫn khấu trừ hay không. Có vẻ như GCC và clang áp dụng các bộ phận ngắt kết nối theo các thứ tự khác nhau. Tôi không nghĩ rằng nó là về sự bất đồng về trật tự một phần, nhưng tôi đang trên Android hiện tại vì vậy tôi không thể nghiên cứu. –

+0

@ JohannesSchaub-litb Bạn có nghĩa là Clang không thực hiện [P0620] (https://wg21.link/P0620)? Có lẽ. Nhưng "tại sao không # 1 đánh bại # 3 khi # 2 làm" câu hỏi là một phần đặt hàng. –

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