Tôi đang đọc bác bỏ quan niệm Mục 13.5 sau đó nêu rằng các toán tử tích hợp không tham gia vào việc giải quyết tình trạng quá tải và lưu ý rằng không có tham chiếu nào đến toán tử->*
phần. Nó chỉ là một toán tử nhị phân tổng quát.
Anh trai của nótoán tử->
,người điều hành*
Vàtoán tử[]
Tất cả đều phải là hàm thành viên không tĩnh. Điều này loại trừ việc xác định quá tải hàm miễn phí như một toán tửnói chung làĐược sử dụng để lấy tham chiếu từ một đối tượng. Nhưng nó không phổ biến toán tử->*
Đã bỏ qua.
Đặc biệt toán tử[]
Có nhiều điểm tương đồng. Nó là nhị phân (họ đã bỏ lỡ một cơ hội vàng để biến nó thành n-ary), nó chấp nhận một số loại container ở bên trái và một số loại định vị ở bên phải. Mục quy định đặc biệt 13.5.5 dường như không có tác dụng thực sự nào, ngoại trừ việc cấm các chức năng miễn phí. (Và hạn chế này thậm chí còn ngăn cản việc hỗ trợ tính giao hoán!)
Ví dụ, đây làhoàn toàn hợp pháp :
#include
#include
sử dụng không gian tên std;
mẫu
T &
toán tử->*( cặp &l, bool r )
{ trả về r? l.second : l.first; }
mẫu
Toán tử T &->*(bool l, cặp &r) { trả về r->*l; }
int chính() {
cặp y( 5, 6 );
y->*(0) = 7;
y->*0->*y = 8; // đánh giá thành 7->*y = y.second
cerr << y.đầu tiên << " " << y.thứ hai << endl;
}
Thật dễ dàng để tìm ra cách sử dụng cho điều này, nhưng cú pháp thay thế thường cũng không tệ đến vậy. Ví dụ,vectơ
Chỉ số thu phóng là:
v->*matrix_width[2][5] = x; // ->* không phải là hoàn toàn lạc lõng
my_indexer<2> m( v, dim ); // my_indexer là kiểu của (v->*width)
m[2][5] = x; // có lẽ thực tế hơn khi chỉ cắt một lần
Liệu ủy ban tiêu chuẩn có quên ngăn chặn điều này không, liệu họ có quyết định rằng nó quá xấu để bận tâm không, hay liệu nó có thực sự hữu ích không?
Ví dụ tốt nhất mà tôi biết làBoost.Phoenix , quá tải toán tử này để thực hiện quyền truy cập thành viên lười biếng.
Đối với những ai chưa quen với Phoenix, đây là một thư viện rất đẹp để xây dựng các Actor (hoặc đối tượng hàm) trông giống như các biểu thức bình thường:
( arg1 % 2 == 1 ) // biểu thức này đánh giá thành một diễn viên
(3); // trả về giá trị true vì 3 % 2 == 1
// các tác nhân này cũng có thể được chuyển sang các thuật toán chuẩn:
std::find_if(c.begin(), c.end(), arg1 % 2 == 1);
// trả về iterator tới phần tử lẻ đầu tiên của c
Nó được tải lại toán tử%
Và toán tử==
Để đạt được các mục tiêu trên. - Áp dụng cho diễn viên đối số1
Các toán tử này trả về một tác nhân khác. Phạm vi các biểu thức có thể được xây dựng theo cách này là cực kỳ lớn:
// in ra từng phần tử trong c, ghi chú giá trị của nó so với 5:
std::for_each(c.begin(), c.end(),
nếu_(arg1 > 5)
[
cout << đối số1 << " > 5\n"
]
.khác_
[
nếu_(arg1 == 5)
[
cout << arg1 << " == 5\n"
]
.khác_
[
cout << arg1 << " < 5\n"
]
]
);
Sau khi sử dụng Phoenix một thời gian (không phải là bạn sẽ quay lại), bạn sẽ thử những điều sau:
typedef std::vector container;
thùng chứa c;
//...
container::iterator inv = std::find_if(c.begin(), c.end(), arg1.ValidStateBit);
std::cout << "MyObj không hợp lệ: " << inv->Id() << std::endl;
Điều này sẽ thất bại, vì tất nhiên là Actor của Phoenix không có thành viên nào Bit trạng thái hợp lệ
. Phượng hoàng bằng cách quá tải toán tử->*
Để giải quyết vấn đề này:
(arg1 ->* &MyObj::ValidStateBit) // đánh giá thành một diễn viên
(validMyObj); // trả về giá trị true
// được sử dụng trong thuật toán của bạn:
container::iterator inv = std::find_if(c.begin(), c.end(),
(arg1->* &MyObj::ValidStateBit));
toán tử->*
Các thông số là:
- Trái: Diễn viên trở lại
MyObj*
- Bên phải:Địa chỉ thành viên
Nó trả về một tác nhân đánh giá LHS và tìm ra thành viên được chỉ định trong đó. (Lưu ý: Bạn thực sự,thực tếMuốn đảm bảo đối số1
trở lại MyObj*
- Bạn sẽ không thấy nhiều lỗi mẫu cho đến khi bạn gặp lỗi gì đó với Phoenix. Chương trình nhỏ này tạo ra 76.738 ký tự đau đớn (Boost 1.54, gcc 4.6):
#include
sử dụng boost::phoenix::placeholders::arg1;
cấu trúc C { int m; };
cấu trúc D { int n; };
int chính() {
( arg1 ->* &D::n ) (C mới);
trả về 0;
}
Tôi là một lập trình viên xuất sắc, rất giỏi!