Gần đây tôi đã đặt câu hỏi tại đây (Detecting instance method constexpr with SFINAE), nơi tôi đã cố gắng thực hiện một số phát hiện constexpr tại thời gian biên dịch. Cuối cùng, tôi đã tìm ra rằng người ta có thể khai thác noexcept
để làm điều này: bất kỳ biểu thức liên tục nào cũng là noexcept
. Vì vậy, tôi cùng nhau đưa các máy móc thiết bị sau:Constexpr decltype
template <class T>
constexpr int maybe_noexcept(T && t) { return 0; }
...
constexpr bool b = noexcept(maybe_noexcept(int{}));
này hoạt động và b
là đúng như bạn mong muốn, như zero-khởi tạo một int
là một biểu thức hằng. Nó cũng tạo ra số không chính xác khi cần (nếu tôi thay đổi int
thành một số loại thích hợp khác).
Tiếp theo, tôi muốn kiểm tra xem có điều gì đó là constexpr
di chuyển có thể cấu hình hay không. Vì vậy, tôi đã làm điều này:
constexpr bool b = noexcept(maybe_noexcept(int(int{})));
Và một lần nữa, điều này hoạt động đúng cho int
hoặc loại do người dùng xác định. Tuy nhiên, điều này kiểm tra xem loại có cả hàm tạo mặc định constexpr và hàm khởi tạo constexpr hay không. Vì vậy, để làm việc xung quanh này, tôi đã cố gắng để thay đổi declval:
constexpr bool b = noexcept(maybe_noexcept(int(declval<int>())));
Điều này dẫn đến b
là sai trong gcc 5.3.0 (không thể sử dụng kêu vang cho bất kỳ này, bởi vì kêu vang không chính xác làm cho liên tục biểu thức noexcept
). Không có vấn đề, tôi nói, phải là vì declval
là (đủ thú vị) không được đánh dấu constexpr
. Vì vậy, tôi viết phiên bản ngây thơ của riêng tôi:
template <class T>
constexpr T&& constexpr_declval() noexcept;
Có, đây là ngây thơ so với cách các thư viện chuẩn thực hiện nó vì nó sẽ nghẹt thở trên khoảng trống và có lẽ những thứ khác, nhưng nó tốt cho bây giờ. Vì vậy, tôi thử lại:
constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));
Điều này vẫn không hoạt động, b
luôn luôn là sai. Tại sao điều này không được coi là một biểu thức liên tục? Đây có phải là lỗi trình biên dịch hay tôi không hiểu cơ bản về constexpr
? Có vẻ như có một số tương tác lạ giữa constexpr
và ngữ cảnh không được đánh giá.
@Cameron Phần thứ hai của những gì bạn nói chắc chắn là đúng, nhưng về mặt kỹ thuật đầu tiên thì không. Mỗi biểu thức liên tục * là * '' noexcept'', nó không phải là nó có thể. Tuy nhiên, sự trở lại của một hàm '' constexpr'' không phải lúc nào cũng là một biểu thức liên tục. –
Lệnh gọi hàm của bạn không phải là biểu thức liên tục vì nó không được định nghĩa ([expr.const] /2.3) – 0x499602D2