2016-08-04 20 views
20

Tìm hiểu về "trình xác định không nhận dạng (và toán tử)", tôi đã viết một mã đơn giản. Và tôi ngạc nhiên rằng đoạn mã này:Làm thế nào hệ thống loại quy tắc ngoại lệ C++ 17 hoạt động?

void asdf() noexcept {} 
int main() 
{ 
    auto f = asdf; 
    std::cout << std::boolalpha << noexcept(f()) << std::endl; 
} 

in false, thậm chí chức năng "asdf" không được chỉ định.

Vì vậy, trong khi tìm kiếm lý do tại sao hiện tượng bí ẩn này đang xảy ra, tôi đã tìm thấy "hệ thống loại quy tắc ngoại lệ của C++ 17" - P0012R1.

Theo đề xuất (được chấp nhận) này, vì C++ 17; như noexcept là một phần của loại chức năng, mã sẽ ở trên có in true không?

Và một nhiều hơn, trong một dòng this câu hỏi của:

std::function<void() noexcept> f 

Các noexcept nêu rõ dường như bỏ qua trong C++ 14 hoặc 11. Sẽ làm việc mã này như dự định trong C++ 17?

+0

g ++ trả về 'true' cho' noexcept (f()) 'mà không có' -std = C++ 1z' ​​(nhưng clang không trả về 'false'). – Holt

+0

Để có thêm niềm vui, hãy thay đổi 'auto f = asdf;' thành 'void (* f)() noexcept = asdf;'. Bây giờ GCC in 'false' trong khi clang in' true'. – hvd

+0

@Holt Cảm ơn thông tin. Tôi đang sử dụng MSVC (trả về 'false'). Điều gì sẽ khác với họ? Đó có phải là lỗi của g ++ hoặc C++ 14 hoặc tiêu chuẩn trước đó không quy định gì về hệ thống kiểu 'noexcept'? – Gear

Trả lời

11

Theo đề xuất (được chấp nhận) này, vì C++ 17; như noexcept là một phần của loại hàm, mã sẽ ở trên có in true không?

Có.

Loại f sẽ được khấu trừ thành void(*)() noexcept vì chuyển đổi chức năng thành con trỏ áp dụng cho asdf sẽ giữ nguyên thuộc tính noexcept. Một cuộc gọi đến một con trỏ chức năng noexcept chắc chắn không thể ném một ngoại lệ, trừ khi một trong các biểu thức con của nó thực hiện.

Để biết từ ngữ chính xác, hãy xem [expr.unary.noexcept]/3[expect.spec]/13. Lưu ý rằng từ ngữ mới trong đoạn sau từ bản thảo C++ 17 xuất phát từ P0012R1, được liên kết trong OP.

Kết quả của các nhà điều hành noexcepttrue nếu tập các trường hợp ngoại lệ tiềm năng của biểu thức ([except.spec]) là trống rỗng, và false khác.

...

  • Nếu e là một lời gọi hàm ([expr.call]):
    • Nếu nó postfix thể hiện là một (có thể trong ngoặc đơn) id-biểu ([expr.prim.id]), quyền truy cập thành viên của lớp ([expr.ref]) hoặc hoạt động trỏ tới thành viên ([expr.mptr.oper]) có biểu thức truyền là một biểu thức id , S là tập hợp các loại trong đặc tả ngoại lệ của thực thể được chọn bởi biểu thức id chứa (sau khi quá tải, nếu có). ...

Vì vậy, các trường hợp ngoại trừ tiềm năng của f() cũng giống như tập các loại trong đặc tả ngoại lệ của f, mà là trống kể từ f được khai báo noexcept.

Hãy chuyển sang câu hỏi thứ hai:

Các noexcept nêu rõ dường như bỏ qua trong C++ 14 hoặc 11. Sẽ làm việc mã này như dự định trong C++ 17?

Câu hỏi của bạn có vẻ như: sẽ std::function<void() noexcept> từ chối giữ chức năng có thể ném ngoại lệ?

Tôi có thể nói rằng đó là không rõ ràng. Trong từ ngữ hiện tại của tiêu chuẩn, std::function<void() noexcept> không thực sự được xác định, giống như std::function<double(float) const> is not defined. Điều này tất nhiên không phải là một vấn đề trong C++ 14, vì noexcept không được coi là một phần của kiểu hàm.

Liệu std::function<void() noexcept> có thể đột nhập vào C++ 17 không? Điều đó không chắc chắn với tôi. Chúng ta hãy nhìn vào từ ngữ hiện tại để đoán hành vi "nên" là gì.

Tiêu chuẩn yêu cầu đối số cho constructor của std::function<R(ArgTypes..)> là "giá trị trái-Callable" cho loại đối số ArgTypes... và kiểu trả về R, mà means:

Một loại callable ([func.def]) FLvalue-Callable đối với loại đối số ArgTypes và trả về loại R nếu biểu thức INVOKE(declval<F&>(), declval<ArgTypes>()..., R), được coi là toán hạng chưa được đánh giá (Điều khoản [expr]), được định dạng tốt ([func.require]).

Có lẽ phải có yêu cầu bổ sung nếu loại chức năng là noexcept, thì noexcept(INVOKE(...)) cũng phải đúng. Tuy nhiên, từ ngữ này không có trong bản nháp hiện tại.

Trong P0012R1, có một nhận xét rằng:

Nó là một vấn đề mở như thế nào để tuyên truyền "noexcept" qua std::function.

Tôi đoán là chúng có nghĩa là không rõ ràng cách std::function có thể được triển khai nếu yêu cầu bổ sung này được áp dụng. Hy vọng rằng, một người khác có thể cung cấp thêm chi tiết.

+1

Rõ ràng chúng ta cần một 'std :: function_moveonly' và' std :: function_noexceptonly' và 'std :: function_moveonly_noexceptonly'. Nhưng những gì về 'std :: function_mutablecall'? Điều này có thể lộn xộn. – Yakk

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