15

Hãy xem xét các cấu trúc sau (?):Các void(), các nhà điều hành dấu phẩy (nhà điều hành,) và những điều không thể quá tải

struct S {}; 

Trong C++ 14, định nghĩa dưới đây là hợp lệ:

constexpr auto f() { return S{}, 'c'; } 

cũng như một sau:

constexpr auto f() { return S{}, void(); } 

Bây giờ, hãy xem xét những điều sau đây, làm việc có liên quan đến đoạn đầu tiên của hai định nghĩa :

#include<type_traits> 

struct S {}; 

constexpr int operator,(S, char) { return 42; } 
constexpr auto f() { return S{}, 'c'; } 

int main() { 
    constexpr int i{f()}; 
    static_assert(i == 42, "!"); 
    static_assert(std::is_same<decltype(f()), int>::value, "!"); 
} 

Phát biểu không quá kỹ thuật, sự quá tải của các nhà điều hành dấu phẩy chặn vài S{}, 'c' và trả về một số nguyên, như xác nhận một cách chính xác trong main chức năng.

Bây giờ, giả sử tôi muốn làm điều tương tự với định nghĩa thứ hai của f:

constexpr auto f() { return S{}, void(); } 

Trong trường hợp này, các nhà điều hành dấu phẩy nên chặn dạng S{}, void().
Cả công trình sau đây định nghĩa (vì lý do rõ ràng):

constexpr int operator,(S, void) { return 42; } 

Cũng không phải hình dưới đây (mà có thể đã làm việc trong trường hợp trước):

template<typename T> constexpr int operator,(S, T &&) { return 42; } 

Có cách nào để quá tải các dấu phẩy toán tử để xử lý S{}, void()?
Không phải là nó thiếu một tiêu chuẩn, vì nó cho phép sử dụng toán tử dấu phẩy theo cách đó, nhưng không cho bạn cơ hội để quá tải cùng một toán tử (ngay cả khi the standard mentions that overloaded functions involving S are allowed)?


Note: Câu hỏi này được thực hiện vì lợi ích của sự tò mò. Xin vui lòng, tránh các ý kiến ​​như không làm điều đó hoặc nó không phải là thực hành tốt. Tôi không có ý định làm điều đó trong môi trường sản xuất. Cảm ơn bạn.

+2

Thật là điên rồ;) –

+0

@JesperJuhl Vâng, tôi biết. Tiêu chuẩn du kích. Tôi đang khám phá các góc tối nghĩa nhất của ngôn ngữ. :-) – skypjack

+0

Thay đổi toán tử ',' thành '+' cho đối số "có thể không có lỗi 'loại' void '. – kennytm

Trả lời

20

Mệnh đề có liên quan của việc này là 13.3.1.2/9 [over.match.oper] trong N4140:

Nếu các nhà điều hành là các nhà điều hành ,, các nhà điều hành unary &, hoặc các nhà điều hành ->, và không có chức năng khả thi, sau đó các nhà điều hành được giả định là được xây dựng trong điều hành và giải thích theo quy định tại khoản 5.

Như void() không bao giờ là một đối số hàm hợp lệ (xem 5.2.2/7 [expr .call]), có ne ver là một hàm khả thi và do đó được xây dựng trong , sẽ được sử dụng.

Vì vậy, không, những gì bạn đang cố gắng làm là không thể.

Trong thực tế, viết một vòng lặp lặp như thế này

for(...; ++it1, (void)++it2) 

là một cách tiêu chuẩn để ngăn chặn người dùng phá vỡ mã của bạn do quá tải , với nhiều loại iterator của họ bằng cách thực thi được xây dựng trong điều hành , được sử dụng. (Lưu ý rằng tôi không nói rằng bạn cần phải làm điều này trong mã hàng ngày của bạn Nó phụ thuộc rất nhiều vào việc sử dụng thực tế của nó Đây là mức tiêu chuẩn thư viện của hoang tưởng...)


Về khoản tiêu chuẩn mà bạn liên kết:

ý nghĩa của các nhà khai thác =, (unary) &, và, (dấu phẩy), được xác định trước cho từng loại, có thể được thay đổi cho lớp và đếm các loại cụ thể bằng cách định nghĩa các chức năng điều hành mà thực hiện các nhà khai thác.

Nhưng chức năng như vậy không thể xác định bởi vì, như tôi đã nói ở trên, void() không bao giờ là đối số hàm hợp lệ.

Bây giờ có hay không đây là sự giám sát/vấn đề trong tiêu chuẩn đang mở để tranh luận.

+2

Sử dụng thú vị '(void)' trên vòng lặp để tránh gọi quá nhiều dấu phẩy. Cảm ơn vì tiền hỗ trợ! – paulotorrens

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