2012-11-06 30 views
18

Giả sử tôi có một chức năng mà phải mất hai đối số,Tại sao các đối tượng được trả lại từ liên kết bỏ qua các đối số thừa?

void f(int x, int y); 

và tôi muốn để ràng buộc một trong số họ. Tôi có thể sử dụng std::bind như sau:

auto partiallyBoundF = std::bind(f, 10, _1); 

partiallyBoundF chỉ mất một đối số, nhưng tôi có thể gọi nó bằng nhiều đối số. Những lập luận ngoài đầu tiên thậm chí không phải là của một loại mà làm cho bất kỳ ý nghĩa:

partiallyBoundF(20, 0); 
partiallyBoundF(0, 44, -99, "Hello", 4.5, true, []{}); 

gì là mục đích của các đối tượng cho phép trở về từ bind để được thông qua lập luận thêm? Nó cho phép các lỗi gọi để biên dịch mà sẽ bị từ chối bất kỳ nơi nào khác.

+3

Trình biên dịch nào? Tôi đoán đây có thể chỉ là một trình biên dịch không phù hợp (bởi vì cho phép các đối số bổ sung đó thực sự không có ý nghĩa gì và tôi nghi ngờ tiêu chuẩn cho phép điều này). Ví dụ, MSVC mô phỏng các mẫu variadic bằng cách chỉ định mỗi mẫu variadic để lấy các đối số mẫu tối đa có thể và mặc định các đối số đó cho một số kiểu NIL. Có lẽ một cái gì đó như thế là nguyên nhân cho hành vi của bạn? –

+3

@ChristianRau: Đó là một phần của tiêu chuẩn. Nó cũng là một phần của TR1. 20.8.2/4 đưa ra nhận xét rằng việc triển khai dự kiến ​​là cho toán tử 'operator()' được biến đổi hóa đơn giản để lấy bất cứ thứ gì được truyền cho nó, bất kể kiểu hoặc số đối số. TR1 có từ ngữ tương tự. – KnowItAllWannabe

+1

Trong trường hợp của bạn, f (w1, ..., wN) trong đó 'N = sizeof ... (bound_args)' (số args để ràng buộc cuộc gọi) phải là một biểu thức hợp lệ, xem 20.8.9.1.2/2 và 20.8.2/1. Chỉnh sửa: Nó không cho phép bất kỳ cách nào khác để gọi nó. – dyp

Trả lời

16

Bỏ qua các đối số bổ sung sẽ đơn giản hơn rất nhiều để triển khai và thực sự hữu ích.

Trong triển khai điển hình, ví dụ: libstdC++ (g ++), cách tiếp cận được thực hiện là thu thập các đối số operator() vào một bộ và sau đó để đối số liên kết std::placeholder trích xuất chúng theo yêu cầu. Việc tính số lượng đối số sẽ yêu cầu đếm số lượng trình giữ chỗ được sử dụng, điều này sẽ khá phức tạp. Lưu ý rằng bindable callable có thể là một hàm functor với nhiều mẫu hoặc gọi là operator(), vì vậy đối tượng bind operator() không thể được tạo ra với một chữ ký "chính xác" duy nhất.

Cũng lưu ý rằng bạn có thể viết:

std::bind(&foo, std::placeholders::_1, std::placeholders::_3); 

ví dụ: bỏ qua một cách rõ ràng đối số thứ hai đến đối tượng ràng buộc. Nếu bind thực thi số đối số của nó, bạn sẽ cần một cách bổ sung để chỉ định rằng ví dụ: một đối số thứ tư cũng bị bỏ qua.

Đối với tính hữu dụng, hãy xem xét ràng buộc một handler tín hiệu thành viên đến một tín hiệu:

sig.connect(std::bind(&C::on_sig, this, param, std::placeholders::_1)); 

Nếu sig có các thông số khí thải phụ không mong muốn, sau đó họ chỉ đơn giản là bỏ qua bởi đối tượng bind; nếu không, ràng buộc cùng một trình xử lý với nhiều tín hiệu sẽ yêu cầu viết nhiều trình bao bọc chuyển tiếp không có mục đích thực sự.

+3

“hữu ích hơn” - tôi đang tranh luận về điều đó. Điều này phá vỡ gõ mạnh mẽ. Và nếu muốn, hành vi này vẫn có thể được mô phỏng với một 'std :: bind' nghiêm ngặt chỉ đơn giản bằng cách sử dụng một functor proxy chấp nhận các đối số variadic. –

+2

@KonradRudolph một biểu thức liên kết không * có * một kiểu được xác định rõ trong trường hợp chung, nếu nó có thể gọi là một functor với nhiều toán tử '()' s. – ecatmur

+0

Bạn có thể bỏ qua một đối số thứ tư bằng cách sử dụng lambda. Không phải là rất tốt đẹp, mặc dù. – dyp

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