1. Vấn đề nó giải quyết
Evaluation operand không rõ có thể làm side effect bất ngờ, còn exception specification trước đây tham gia hạn chế vào type relationship. C++17 tăng một số sequencing rule và đưa noexcept vào function type.
2. Kiến thức cần có
Compiler hỗ trợ C++17, được gọi với warning đầy đủ, cùng các bài trước theo thứ tự của khóa học.
Biết side effect, sequencing, function pointer, exception specification và
std::is_nothrow_invocable.
3. Ý tưởng cốt lõi
Với assignment trong C++17, right operand được sequenced trước left operand. Riêng function pointer type có thể yêu cầu function không throw, cho phép phân biệt compile time giữa target có thể throw và noexcept.
4. Cú pháp tối thiểu
using Safe = void (*)() noexcept;
Safe action = &safe_action;
values[index()] = produce();5. Cách nó hoạt động
Helper có logging làm lộ việc evaluate right side của assignment trước indexed left side.
Function pointer
noexceptcùng type trait sau đó kiểm tra non-throwing callable contract.Chương trình in
valuetrướcindex, rồi số đã lưu và text từ safe action, tạo test oracle nhỏ để so sánh với dự đoán trước khi biên dịch.
6. Lỗi thường gặp
C++17 không áp dụng quy tắc left-to-right đơn giản cho mọi function argument; không dựa vào order nếu không có sequencing rule cụ thể.
Build thành công chưa đủ; phải kiểm tra lifetime, ordering và error path.
7. Khi nào nên dùng
Nên dùng kỹ thuật này khi review expression có side effect hoặc mã hóa non-throwing callback contract trong type.
Nên chọn cách C++11/14 đơn giản hơn nếu quy tắc C++17 không cải thiện safety, độ rõ hoặc hiệu năng đã đo trên các toolchain phải hỗ trợ.
8. Ví dụ đơn giản
Assignment dùng function logging riêng để order nhìn thấy được. Static assertion xác nhận function pointer được chọn là nothrow-invocable.
Mã mẫu hoàn chỉnh
Tệp mã nguồn
cpp17/22_evaluation_order_noexcept_function_type/main.cpp
#include <array>
#include <iostream>
#include <type_traits>
int index() {
std::cout << "index\n";
return 0;
}
int produce() {
std::cout << "value\n";
return 42;
}
void safe_action() noexcept {
std::cout << "safe action\n";
}
int main() {
std::array<int, 1> values{};
values[index()] = produce(); // right operand is sequenced first
using Safe = void (*)() noexcept;
Safe action = &safe_action;
static_assert(std::is_nothrow_invocable_v<Safe>);
std::cout << "stored: " << values[0] << '\n';
action();
}
9. Điều cần nhớ
Suy luận từ sequencing rule chính xác và xem
noexceptlà một phần callable type compatibility trong C++17.Phải chọn rõ chế độ C++17; default của compiler mới hơn có thể che lỗi portability.
Warning và ví dụ xác định biến quy tắc ghi nhớ thành bằng chứng.
10. Câu hỏi tự kiểm tra
Dễ — Evaluation order và noexcept trong function type giải quyết vấn đề chính nào?
Trung bình — Từ logging nào xuất hiện trước trong assignment expression?
Khó — Conversion nào được phép giữa throwing và non-throwing function pointer?