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, foo
khô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 J
phải K
, giả sử dạng trong function bar
như 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 [] { }
là fuction bar
và ở phạm vi đó, không có foo
thể đượ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 zap
như giống như zap
, nó có nghĩa là không gian tên của [] { }
là K
, Bây giờ foo
có thể được tìm thấy trong không gian tên chaJ
bở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 func
là 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 #1
và 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 )
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ênJ::K
, không nằm trong định nghĩabar
, 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.