Cách hiểu độ phân giải được đề xuất của # 1664


8

Sau khi xem độ phân giải được đề xuất của # 1664 ( độ phân giải được đề xuất 1664 ), tôi bối rối cho các quy tắc của một đối số mặc định của mẫu hàm, Trích dẫn nội dung ở đây:

Theo 8.1.5 [expr.prim.lambda] đoạn 3

Kiểu đóng được khai báo trong phạm vi khối nhỏ nhất, phạm vi lớp hoặc phạm vi không gian tên có chứa biểu thức lambda tương ứng. [Lưu ý: Điều này xác định tập hợp các không gian tên và các lớp được liên kết với kiểu đóng (6.4.2 [basic.lookup.argdep]). Các kiểu tham số của bộ khai báo lambda không ảnh hưởng đến các không gian tên và các lớp liên quan này. Lưu ý

Tuy nhiên, 17.8.1 [temp.inst] đoạn 13 nói

Nếu một mẫu hàm f được gọi theo cách yêu cầu sử dụng đối số mặc định, các tên phụ thuộc được tra cứu, các ràng buộc ngữ nghĩa được kiểm tra và việc khởi tạo bất kỳ mẫu nào được sử dụng trong đối số mặc định được thực hiện như thể đối số mặc định đã là một trình khởi tạo được sử dụng trong chuyên môn hóa mẫu hàm với cùng phạm vi, cùng tham số mẫu và cùng truy cập với mẫu của hàm f được sử dụng tại thời điểm đó.

Do đó, một khả năng là kiểu đóng cho biểu thức lambda trong một đối số mặc định cho hàm mẫu (hoặc, có lẽ là hàm thành viên của mẫu lớp) được coi là đã được khai báo trong một phạm vi khối trong phần thân của chuyên môn mẫu chức năng hư cấu.

Hãy xem xét ví dụ sau:

 namespace J {
    inline namespace K {
      template <typename T> int zap(const T &t) { foo(t); return 0; }
      template <typename T> void zip(int = zap([] { })) { }
    }
    template <typename T> void foo(const T &) { }
  }
  void bar() { 
    J::K::zip<long>(); 
    /*Accroding to the above wording,the invoke just like:  
      => J::K::zip<long>(zap([] { })); 
   */
  }

Nếu zip không phải là một mẫu, tra cứu phụ thuộc vào đối số sẽ giải quyết thành công việc tra cứu foo trong tất cả các triển khai được kiểm tra; tuy nhiên, có phương sai thực hiện trong việc xử lý ví dụ như được viết.

Dự kiến ​​nghị quyết (tháng 9 năm 2013):

Thay đổi 17.8.1 [temp.inst] đoạn 13 như sau:
Nếu một mẫu hàm f được gọi theo cách yêu cầu một đối số mặc định được sử dụng, các tên phụ thuộc được tra cứu, các ràng buộc ngữ nghĩa được kiểm tra và khởi tạo bất kỳ mẫu nào được sử dụng trong đối số mặc định đều được thực hiện như thể đối số mặc định là trình khởi tạo được sử dụng trong chuyên môn mẫu hàm với cùng phạm vi, cùng tham số mẫu và cùng truy cập như mẫu của hàm f được sử dụng tại điểm đó, ngoại trừ rằng phạm vi trong đó một kiểu đóng được khai báo (8.1.5 [expr.prim.lambda]) - và do đó, các không gian tên liên quan của nó - vẫn được xác định từ ngữ cảnh của định nghĩa cho đối số mặc định. Phân tích này được gọi là khởi tạo đối số mặc định. Đối số mặc định được khởi tạo sau đó được sử dụng làm đối số của f.

Lưu ý phần được nhấn mạnh, nếu tôi không hiểu sai, Điều đó có nghĩa là nếu phần nhấn mạnh nhận xét, fookhông thể tra cứu bằng cách tìm kiếm phụ thuộc đối số bởi vì đối số [] { }không gian tên cũng không Jphải K, giả sử dạng trong function barnhư thế J::K::zip<long>(zap([] { }) /*default argument*/);, do đó, hãy truy cập vào [ expr.prim.lambda] đoạn 3 không gian tên của [] { }fuction barvà ở phạm vi đó, không có foothể được tìm thấy, vì vậy, phần nhấn mạnh là đối với trường hợp này mà xem xét không gian tên của [] { }bên trong zapnhư giống như zap, nó có nghĩa là không gian tên của [] { }K, Bây giờ foocó thể được tìm thấy trong không gian tên chaJbởi các quy tắc tra cứu phụ thuộc đối số, cho đến nay, nếu tôi hiểu sai các quy tắc này, vui lòng sửa lại cho tôi. Quan điểm khác là đối số mặc định được đánh giá mỗi khi hàm được gọi, ngay cả khi mặc định là không phụ thuộc . mã sau:

#include <iostream>
struct A {

};
template<typename T>
int func(T, float) {  //#a
    std::cout << "float" << std::endl;
    return 0;
}
template<typename T>
void test(int = func(A{}, 0)) { //#1

}
template<typename T>
int func(T, int) {  //#b
    std::cout << "int" << std::endl;
    return 0;
}
int main() {
    test<A>(); //#2 transform to: test<A>(func(A{}, 0)); here,#b should be the best match
    std::getchar();
}

Mặc dù đối số mặc định funclà không phụ thuộc, tuy nhiên nó phải được xác định mỗi khi hàm testđược gọi và tôi kiểm tra mã trong một số trình biên dịch.
Tất cả các phiên bản của báo cáo MSVC "int", báo cáo gcc "phao", báo cáo kêu vang "phao", những gì là địa ngục? Accroding để báo cáo của gcc hoặc kêu vang, Dường như với những funcđược xác định tại #1và MSVC chứng minh rằng sự funcđược xác định tại #2. nếu MSVC sai, điều đó có nghĩa là đối số mặc định không phụ thuộc có thể được xác định trong # 1 và không cần thiết phải xác định mỗi khi hàm được gọi, tại sao phần nhấn mạnh cần thêm? (Nếu tôi hiểu chính xác phần được nhấn mạnh, mục đích của nó là giữ cho không gian tên của kiểu đóng trong đối số mặc định phù hợp cho dù biểu thức lambda nằm ở điểm khai báo hàm hay điểm gọi ). Nếu tôi hiểu sai các quy tắc này, làm thế nào để giải thích chúng một cách chính xác?

CẬP NHẬT:

phiên bản 9.1 trở lên của gcc không thể tuân thủ mã được đề cập trong # 1664, nó sẽ báo lỗi ( kết quả tuân thủ )

Câu hỏi:

1. Đối số mặc định không phụ thuộc của mẫu hàm hoặc hàm không phải mẫu cần xác định mỗi khi hàm tương ứng được gọi?

2.What không "định nghĩa cho các đối số mặc định" nghĩa là gì? Là từ ngữ này đúng? ( Nói một cách khác, sự hiểu biết của tôi là, những gì actullay các quy tắc bổ sung muốn bày tỏ là không gian tên của loại closeure là của một hàm declartion nơi chứa một đối số mặc định có chứa biểu thức lambda tương ứng, phải không? nếu sự hiểu biết của tôi về điều này là sai, hãy sửa cho tôi )


1
"cùng phạm vi ... giống như mẫu hàm fđược sử dụng" thực sự nghe có vẻ như chuyên môn giả định sẽ nằm trong không gian tên J::K, không nằm trong định nghĩa bar, nhưng sau đó tôi không thấy cụm từ thay đổi sẽ tạo ra sự khác biệt như thế nào.
aschepler

Tôi hiểu tất cả những điều đó, nhưng tôi không nghĩ rằng chúng tôi đã kết luận điều tương tự từ cách diễn đạt trước phần thay đổi / in đậm.
aschepler

1
"Bây giờ, tôi bắt đầu một tiền thưởng cho câu hỏi bổ sung." Đây không phải là cách StackOverflow hoạt động. Nếu bạn có một câu hỏi mới, hãy hỏi một câu hỏi mới. Một câu hỏi cho mỗi câu hỏi. Tôi quay lại chỉnh sửa của bạn.
Barry

@Barry Tôi nghĩ rằng câu hỏi cập nhật thuộc về "Cách hiểu độ phân giải được đề xuất của # 1664"
jack X

Xin lỗi, bạn cần đăng câu hỏi mới . Stack Overflow ở đây để xây dựng một kho chứa các câu hỏi hữu ích và câu trả lời của họ cho khách truy cập trong tương lai và bây giờ câu hỏi đầu tiên của bạn đã có câu trả lời, chúng tôi xem toàn bộ trang này. Vui lòng tôn trọng công việc mà người trả lời đã đưa vào để cung cấp giải pháp và đưa câu hỏi mới vào bài đăng câu hỏi mới. Việc thay đổi (mở rộng) vấn đề ở đây sẽ làm mất hiệu lực câu trả lời của họ và làm cho bài đăng của bạn không có chủ đề (đóng cửa vì cần phải tập trung hơn nữa).
Martijn Pieters

Câu trả lời:


3

Các đối số mặc định được đánh giá mỗi khi chúng được gọi, nhưng đây là thuộc tính thời gian chạy: các cuộc gọi được tính không phải bởi dòng nguồn mà bởi luồng điều khiển thực tế. Một cách riêng biệt, một đối số mặc định cho hàm templated được coi là một định nghĩa và được khởi tạo khi cần, tối đa một lần cho mỗi chuyên môn hóa của hàm (với điều kiện thông thường về nhiều điểm khởi tạo phải đồng ý). CWG1664 là một vấn đề rất hẹp dựa trên cách diễn đạt của từ đó : bằng cách giới thiệu một mẫu hàm giả tưởng , nó để ngỏ khả năng tuyên bố vật lý của lambda đã di chuyển. Việc khắc phục thực sự chỉ ảnh hưởng đến ADL.

Bạn funcví dụ thay vì mô tả các quy tắc tên tra cứu thông thường trong các mẫu: dù có bao nhiêu lần và từ đâu test ‘s đối số mặc định được khởi tạo, functrong đó không phải là một phụ thuộc tên và do đó phát hiện func(T,float)(mỗi lần). MSVC nổi tiếng chưa bao giờ thực hiện quy tắc này một cách chính xác (bởi vì, công bằng mà nói, việc triển khai của họ có trước quy tắc và gần đây họ mới bắt đầu viết lại yêu cầu (và gần như hoàn thành) về hỗ trợ mẫu của họ).

Trong khi đó, GCC gần đây có lỗi rõ ràng với ví dụ CWG1664: lưu ý rằng nó phàn nàn về việc foođược sử dụng nhưng không được xác định, mâu thuẫn với cả { }thông báo lỗi rõ ràng và thông báo lỗi trước đó về việc không tìm thấy nó.


Tôi cố gắng tóm tắt sự hiểu biết của tôi về câu trả lời của bạn.1. Đối với đối số mặc định, nếu chúng là tên không phụ thuộc, tên được ràng buộc như được viết tại thời điểm đó (như [dcl.fct.default] / 5 đã nói), thay vào đó, tên phụ thuộc là cần thiết để tra cứu tên mỗi khi hàm gọi là. 2.Đối với biểu thức lambda, vì nó không phải là một tên, vì vậy nó không thể bị ràng buộc ngay cả khi đối số mặc định không phụ thuộc, do đó, nếu không có phần nhấn mạnh nào để ràng buộc, kiểu đóng sẽ có không gian tên khác nhau theo điểm của cuộc gọi nơi không gian tên bao trùm nó. Bạn có đồng ý không?
jack X

Một câu hỏi khác từ câu trả lời của bạn tôi cần nói riêng là "Có phải" chuyên môn hóa mẫu chức năng hư cấu "đề cập đến" J :: K :: zip <long> (); ", chứ không phải là định nghĩa của" J :: K :: zip <long> () "tại điểm khởi tạo?
jack X

@jackX: Đó là và [temp.nondep] / 1 cho các tên không phụ thuộc; tên phụ thuộc được tìm kiếm cho mỗi lần khởi tạo cho dù chúng có xuất hiện trong một đối số mặc định hay không. Kiểu đóng sẽ thuộc về chuyên môn mẫu hàm giả tưởng (không phải là một cuộc gọi cũng như bất kỳ định nghĩa thực tế nào zip).
Davis Herring

vì vậy, "chuyên môn hóa mẫu hàm giả tưởng" đề cập đến một cái gì đó như "J :: K :: zip <long> ();"? và hiệu quả của "ngoại trừ phạm vi mà kiểu đóng được khai báo", tôi nghĩ rằng câu theo sau nó: "và do đó không gian tên liên quan của nó - vẫn được xác định từ ngữ cảnh của định nghĩa cho đối số mặc định" là đủ tới ADL
jack X

@jackX: Tôi chỉ nói rằng nó không được tham khảo. Phạm vi là quy tắc thực tế: không gian tên là một hệ quả, ngay cả khi chúng mang tất cả nhập khẩu.
Davis Herring
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.