Bất kỳ lý do không sử dụng lambdas toàn cầu?


89

Chúng tôi có một chức năng sử dụng nội bộ lambda không bắt giữ cho chính nó, ví dụ:

void foo() {
  auto bar = [](int a, int b){ return a + b; }

  // code using bar(x,y) a bunch of times
}

Bây giờ chức năng được thực hiện bởi lambda trở nên cần thiết ở nơi khác, vì vậy tôi sẽ nâng lambda ra khỏi foo()phạm vi toàn cầu / không gian tên. Tôi có thể để nó dưới dạng lambda, biến nó thành tùy chọn sao chép hoặc thay đổi nó thành một chức năng phù hợp:

auto bar = [](int a, int b){ return a + b; } // option 1
int bar(int a, int b){ return a + b; } // option 2

void foo() {
  // code using bar(x,y) a bunch of times
}

Thay đổi nó thành một chức năng phù hợp là chuyện nhỏ, nhưng nó khiến tôi tự hỏi liệu có lý do nào để không để nó như một lambda không? Có lý do nào để không sử dụng lambdas ở mọi nơi thay vì các chức năng toàn cầu "thông thường" không?


Tôi cho rằng việc nắm bắt các biến không lường trước sẽ dẫn đến nhiều lỗi nếu lambdas không được sử dụng cẩn thận
macroland

Câu trả lời:


61

Có một lý do rất quan trọng để không sử dụng lambdas toàn cầu: bởi vì nó không bình thường.

Cú pháp hàm thông thường của C ++ đã xuất hiện từ thời C. Các lập trình viên đã biết trong nhiều thập kỷ, nói cú pháp nghĩa là gì và cách họ làm việc (mặc dù phải thừa nhận rằng toàn bộ điều phân rã hàm-con trỏ đôi khi cắn cả những lập trình viên dày dạn). Nếu một lập trình viên C ++ ở bất kỳ cấp độ kỹ năng nào ngoài "người mới hoàn toàn" nhìn thấy một định nghĩa hàm, họ sẽ biết họ đang nhận được gì.

Một lambda toàn cầu là một con thú khác nhau hoàn toàn. Nó có hành vi khác với một chức năng thông thường. Lambdas là đối tượng, trong khi chức năng thì không. Họ có một loại, nhưng loại đó khác với loại chức năng của họ. Và kể từ đó trở đi.

Vì vậy, bây giờ, bạn đã nâng tầm trong việc giao tiếp với các lập trình viên khác. Một lập trình viên C ++ cần phải hiểu lambdas nếu họ sẽ hiểu chức năng này đang làm gì. Và vâng, đây là năm 2019, vì vậy một lập trình viên C ++ đàng hoàng nên có ý tưởng về một lambda trông như thế nào. Nhưng nó vẫn là một thanh cao hơn.

Và ngay cả khi họ hiểu nó, câu hỏi trong đầu của lập trình viên đó sẽ là ... tại sao người viết mã này lại viết như vậy? Và nếu bạn không có câu trả lời hay cho câu hỏi đó (ví dụ: vì bạn rõ ràng muốn cấm quá tải, như trong các điểm tùy chỉnh Phạm vi), thì bạn nên sử dụng cơ chế chung.

Thích các giải pháp dự kiến ​​cho những cuốn tiểu thuyết khi thích hợp. Sử dụng phương pháp ít phức tạp nhất để có được điểm của bạn.


9
"Kể từ thời của C" Cách trước đó, bạn của tôi
Cuộc đua ánh sáng trong quỹ đạo

4
@LightnessRaces: Quan điểm chính của tôi là thể hiện rằng cú pháp hàm của C ++ đã có từ C, vì vậy rất nhiều người biết nó là gì khi kiểm tra.
Nicol Bolas

2
Đồng ý với tất cả câu trả lời này ngoại trừ câu đầu tiên. "Nó không bình thường" là một tuyên bố mơ hồ và mơ hồ. Có lẽ bạn có nghĩa nó theo nghĩa "nó không phổ biến và khó hiểu"?
einpoklum

1
@einpoklum: C ++ có nhiều thứ có thể được coi là "không phổ biến và khó hiểu" vẫn còn khá "bình thường" trong miền của họ (xem siêu lập trình mẫu sâu). Tôi nghĩ "bình thường" là hoàn toàn hợp lệ trong trường hợp này; nó không phải là một thứ nằm trong "chuẩn mực" của kinh nghiệm lập trình C ++, cả trong lịch sử và ngày nay.
Nicol Bolas

@NicolBolas: Nhưng theo nghĩa đó, đó là lý do vòng tròn: OP đang tự hỏi liệu chúng ta có nên áp dụng một thực tiễn hiếm. Các thực hành hiếm hoi không phải là "chuẩn mực", gần như theo định nghĩa. Nhưng bước sóng.
einpoklum

53

Tôi có thể nghĩ ra một vài lý do bạn muốn tránh lambdas toàn cầu như là sự thay thế thả vào cho các chức năng thông thường:

  • chức năng thông thường có thể bị quá tải; lambdas không thể (tuy nhiên có các kỹ thuật để mô phỏng điều này)
  • Mặc dù thực tế là chúng giống như chức năng, ngay cả một lambda không bắt như thế này sẽ chiếm bộ nhớ (thường là 1 byte cho việc không bắt).
    • như đã chỉ ra trong các bình luận, các trình biên dịch hiện đại sẽ tối ưu hóa bộ lưu trữ này theo quy tắc as-if

"Tại sao tôi không nên sử dụng lambdas để thay thế functor nhà nước (lớp)?"

  • các lớp chỉ đơn giản là có ít hạn chế hơn lambdas và do đó nên là điều đầu tiên bạn tiếp cận
    • (dữ liệu công khai / riêng tư, quá tải, phương thức trợ giúp, v.v.)
  • nếu lambda có nhà nước, thì tất cả sẽ khó khăn hơn để lý do khi nó trở thành toàn cầu.
    • Chúng ta nên tạo một thể hiện của một lớp ở phạm vi hẹp nhất có thể
  • thật khó để chuyển đổi lambda không bắt giữ thành một con trỏ hàm và không thể cho lambda chỉ định bất cứ điều gì trong quá trình bắt giữ.
    • các lớp cho chúng ta một cách đơn giản để tạo các con trỏ hàm và chúng cũng là thứ mà nhiều lập trình viên cảm thấy thoải mái hơn
  • Lambdas với bất kỳ sự bắt giữ nào cũng không thể được xây dựng mặc định (trong C ++ 20. Trước đây không có hàm tạo mặc định nào trong mọi trường hợp)

Ngoài ra còn có con trỏ "này" ẩn với lambda (thậm chí là không bắt được) dẫn đến một tham số phụ khi gọi lambda so với gọi hàm.
1201 Chương trình Chương trình

@ 1201ProgramAlarm: Đó là một điểm tốt; Có thể khó hơn nhiều để có được một con trỏ hàm cho lambda (mặc dù lambdas không bắt có thể phân rã thành các con trỏ hàm thông thường)
AndyG

3
Mặt khác, nếu nó được truyền đi đâu đó thay vì được gọi trực tiếp, có lambda thay vì chức năng thúc đẩy nội tuyến. Đương nhiên, người ta có thể đóng gói con trỏ hàm theo cách std::integral_constantđó ...
Ded repeatator

@Ded repeatator: " có lambda thay vì hàm thúc đẩy nội tuyến " Chỉ cần rõ ràng, điều này chỉ áp dụng nếu "ở đâu đó" là một mẫu có chức năng mà nó gọi là một loại có thể gọi tùy ý, thay vì con trỏ hàm.
Nicol Bolas

2
@AndyG Bạn đang quên quy tắc as-if: Các chương trình không yêu cầu kích thước của lambda (vì tại sao?!), Cũng không tạo con trỏ cho nó, không cần (và nói chung là không) phân bổ không gian cho nó.
Konrad Rudolph


8

Có lý do nào để không sử dụng lambdas ở mọi nơi thay vì các chức năng toàn cầu "thông thường" không?

Một vấn đề về mức độ phức tạp nhất định đòi hỏi một giải pháp ít nhất là cùng độ phức tạp. Nhưng nếu có một giải pháp ít phức tạp hơn cho cùng một vấn đề, thì thực sự không có lý do nào để sử dụng giải pháp phức tạp hơn. Tại sao lại giới thiệu sự phức tạp mà bạn không cần?

Giữa lambda và hàm, một hàm đơn giản là loại thực thể ít phức tạp hơn của hai. Bạn không cần phải biện minh cho việc không sử dụng lambda. Bạn phải biện minh bằng cách sử dụng một. Một biểu thức lambda giới thiệu một kiểu đóng, là một loại lớp không tên với tất cả các hàm thành viên đặc biệt thông thường, một toán tử gọi hàm và, trong trường hợp này, một toán tử chuyển đổi ẩn thành con trỏ hàm và tạo một đối tượng của kiểu đó. Sao chép-khởi tạo một biến toàn cục từ một biểu thức lambda chỉ đơn giản là làm nhiều hơn là chỉ xác định một hàm. Nó định nghĩa một loại lớp với sáu hàm được khai báo ngầm, định nghĩa thêm hai hàm toán tử và tạo một đối tượng. Trình biên dịch phải làm nhiều hơn nữa. Nếu bạn không cần bất kỳ tính năng nào của lambda, thì đừng sử dụng lambda Chế


6

Lambdas là các chức năng ẩn danh .

Nếu bạn đang sử dụng lambda có tên, điều đó có nghĩa là về cơ bản bạn đang sử dụng một hàm ẩn danh có tên. Để tránh oxymoron này, bạn cũng có thể sử dụng một chức năng.


1
Đây dường như là một đối số từ thuật ngữ, tức là. đặt tên khó hiểu và ý nghĩa. Nó có thể dễ dàng bị bác bỏ bằng cách định nghĩa rằng lambda có tên không còn ẩn danh (duh). Vấn đề ở đây không phải là cách lambda được sử dụng, đó là chức năng ẩn danh của người Hồi giáo là một cách viết sai và không còn chính xác khi lambda bị ràng buộc với một tên.
Konrad Rudolph

@KonradRudolph: Đây không chỉ là thuật ngữ, đó là lý do tại sao chúng được tạo ra ngay từ đầu. Ít nhất trong lịch sử, lambdas là các chức năng ẩn danh và đó là lý do tại sao nó khó hiểu khi đặt tên cho chúng, đặc biệt là khi các chức năng sẽ được mong đợi thay thế.
Eric Duminil

1
Không Lambdas được đặt tên thường xuyên (thường là địa phương), không có gì khó hiểu về điều đó.
Konrad Rudolph

1
Không đồng ý với các hàm ẩn danh , nó là một functor hơn, nhưng dù sao, tôi không thấy vấn đề phải có cá thể (được đặt tên) thay vì buộc chỉ sử dụng chúng làm tham chiếu giá trị. (như quan điểm của bạn cũng nên áp dụng ở phạm vi địa phương).
Jarod42

5

nếu có một số lý do để không để nó như một lambda? Có lý do nào để không sử dụng lambdas ở mọi nơi thay vì các chức năng toàn cầu "thông thường" không?

Chúng tôi thường sử dụng các chức năng thay vì functor toàn cầu, vì vậy nó phá vỡ sự gắn kết và Nguyên tắc ít gây ngạc nhiên nhất .

Sự khác biệt chính là:

  • các chức năng có thể bị quá tải, trong khi functor thì không thể.
  • chức năng có thể được tìm thấy với ADL, không phải functor.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.