Trong +
biểu thức +[](){}
là toán +
tử một ngôi. Nó được định nghĩa như sau trong [expr.unary.op] / 7:
Toán hạng của toán +
tử một ngôi phải có kiểu số học, kiểu liệt kê không ghi hoặc kiểu con trỏ và kết quả là giá trị của đối số.
Lambda không thuộc loại số học, v.v., nhưng nó có thể được chuyển đổi:
[expr.prim.lambda] / 3
Kiểu của lambda-expression [...] là một kiểu lớp không liên hợp duy nhất, không được đặt tên - được gọi là kiểu đóng - có các thuộc tính được mô tả bên dưới.
[expr.prim.lambda] / 6
Kiểu đóng cửa cho một lambda thể hiện không có lambda-chụp có một public
phi virtual
phi explicit
const
chức năng chuyển đổi để con trỏ đến chức năng có các loại tham số và lợi nhuận tương tự như hàm operator gọi kiểu đóng của. Giá trị được trả về bởi hàm chuyển đổi này sẽ là địa chỉ của một hàm mà khi được gọi ra, nó có tác dụng giống như việc gọi toán tử gọi hàm của kiểu đóng.
Do đó, hàm đơn nguyên +
buộc chuyển đổi sang kiểu con trỏ hàm, dành cho lambda này void (*)()
. Do đó, kiểu của biểu thức +[](){}
là kiểu con trỏ hàm này void (*)()
.
Quá tải thứ hai void foo(void (*f)())
trở thành Đối sánh chính xác trong xếp hạng để giải quyết quá tải và do đó được chọn rõ ràng (vì quá tải đầu tiên KHÔNG phải là Đối sánh chính xác).
Lambda [](){}
có thể được chuyển đổi thành std::function<void()>
thông qua ctor mẫu không rõ ràng std::function
, lấy bất kỳ kiểu nào đáp ứng các yêu cầu Callable
và CopyConstructible
.
Lambda cũng có thể được chuyển đổi thành void (*)()
thông qua hàm chuyển đổi của kiểu đóng (xem ở trên).
Cả hai đều là chuỗi chuyển đổi do người dùng xác định và có cùng thứ hạng. Đó là lý do tại sao giải quyết quá tải không thành công trong ví dụ đầu tiên do không rõ ràng.
Theo Cassio Neri, được hỗ trợ bởi một lập luận của Daniel Krügler, +
thủ thuật đơn lẻ này nên được chỉ định hành vi, tức là bạn có thể dựa vào nó (xem thảo luận trong phần bình luận).
Tuy nhiên, tôi khuyên bạn nên sử dụng kiểu ép kiểu rõ ràng cho kiểu con trỏ hàm nếu bạn muốn tránh sự mơ hồ: bạn không cần phải hỏi SO là gì và tại sao nó hoạt động;)
std::bind
mộtstd::function
đối tượng có thể được gọi tương tự như một hàm lvalue.