2011-01-18 44 views
61

Tôi tự hỏi liệu có thể viết một hàm trả về hàm lambda trong C++ 11 hay không. Tất nhiên một vấn đề là làm thế nào để khai báo chức năng như vậy. Mỗi lambda có một kiểu, nhưng kiểu đó không thể hiện rõ trong C++. Tôi không nghĩ rằng điều này sẽ làm việc:Chức năng trả về biểu thức lambda

auto retFun() -> decltype ([](int x) -> int) 
{ 
    return [](int x) { return x; } 
} 

Cũng không này:

int(int) retFun(); 

Tôi không nhận thấy bất kỳ chuyển đổi tự động từ lambdas đến, nói rằng, con trỏ đến chức năng, hoặc một số ví dụ. Là giải pháp duy nhất thủ công một đối tượng chức năng và trả lại nó?

+0

Để thêm những gì đã được nói, chức năng lambda không quốc tịch có thể chuyển đổi thành con trỏ hàm. –

+2

IMO tùy chọn đầu tiên của bạn sẽ không hoạt động vì lambda trong 'decltype' không giống như trong phần tử hàm và do đó có một kiểu khác (ngay cả khi bạn đưa vào câu lệnh return) – Motti

+1

Bằng cách này, nếu một lambda có một mệnh đề capture trống, nó có thể được chuyển đổi hoàn toàn thành một con trỏ trỏ tới hàm. – GManNickG

Trả lời

70

Bạn không cần một đối tượng chức năng làm thủ công, chỉ cần sử dụng std::function, mà hàm lambda là mui trần:

std::function<int (int)> retFun() { 
    return [](int x) { return x; }; 
} 
+4

Duh! Tôi yêu StackOverflow. Nó sẽ khiến tôi mất nhiều thời gian hơn để nghiên cứu chủ đề rồi nhận được câu trả lời trên StackOverflow. Cảm ơn Sean! –

+3

Điều đó sẽ gây ra sự phân bổ bộ nhớ mặc dù trong hàm tạo của 'std :: function'. –

+2

@Maxim Yegorushkin std :: chức năng di chuyển ngữ nghĩa cộng với nó có thể sử dụng phân bổ tùy chỉnh và bản thảo làm việc C++ 0x có các ghi chú sau: "[Ghi chú: triển khai được khuyến khích tránh sử dụng bộ nhớ được cấp phát động cho các đối tượng nhỏ, Ví dụ, trong đó mục tiêu của f là một đối tượng chỉ giữ một con trỏ hoặc tham chiếu đến một đối tượng và một con trỏ hàm thành viên. có thể sử dụng phân bổ của riêng bạn (gộp). –

27

Ví dụ đơn giản này, bạn không cần phải std::function.

Từ tiêu chuẩn §5.1.2/6:

Kiểu đóng cửa cho một lambda-biểu không có lambda-chụp có chức năng chuyển đổi nào không ảo không rõ ràng const để con trỏ có chức năng có cùng tham số và kiểu trả về như toán tử gọi hàm của loại đóng. Giá trị trả về bởi hàm chuyển đổi này sẽ là địa chỉ của hàm mà khi được gọi, có cùng tác dụng như gọi toán tử gọi hàm của loại đóng.

Bởi vì chức năng của bạn không có một nắm bắt, nó có nghĩa là lambda có thể được chuyển đổi sang một con trỏ đến chức năng của loại int (*)(int):

typedef int (*identity_t)(int); // works with gcc 
identity_t retFun() { 
    return [](int x) { return x; }; 
} 

Đó là sự hiểu biết của tôi, chính xác cho tôi nếu tôi sai rồi.

+1

Điều này nghe có vẻ đúng. Thật không may, nó không hoạt động với trình biên dịch hiện tại tôi đang sử dụng: VS 2010. std :: chức năng chuyển đổi xảy ra để làm việc. –

+3

Có, từ ngữ cuối cùng của quy tắc này đã quá muộn cho VC2010. –

+0

Tôi đã thêm ví dụ về mã. Đây là [full program] (https://gist.github.com/1342212). – jfs

12

Bạn có thể trả về hàm lambda từ hàm lambda khác, vì bạn không nên chỉ định rõ ràng kiểu trả về của hàm lambda. Chỉ cần viết một cái gì đó như thế trong phạm vi toàn cầu:

auto retFun = []() { 
    return [](int x) {return x;}; 
}; 
+2

Điều đó chỉ đúng khi lambda bên ngoài chỉ bao gồm câu lệnh return. Nếu không, bạn phải xác định kiểu trả về. –

+1

Đây là câu trả lời hay nhất vì nó không yêu cầu đa hình thời gian chạy của hàm std :: và cho phép lambda có danh sách chụp không trống, tuy nhiên tôi sẽ sử dụng ** const ** auto fun = ... –

10

Mặc dù câu hỏi đặc biệt hỏi về C++ 11, vì lợi ích của những người khác sau khi vấp ngã này và được tiếp cận với một trình biên dịch C++ 14, C++ 14 giờ đây cho phép loại bỏ các kiểu trả về cho các hàm bình thường. Vì vậy, ví dụ trong câu hỏi có thể được điều chỉnh chỉ để làm việc như mong muốn chỉ đơn giản bằng cách thả các -> decltype ... khoản sau khi danh sách tham số chức năng:

auto retFun() 
{ 
    return [](int x) { return x; } 
} 

Lưu ý, tuy nhiên, điều này sẽ không làm việc nếu có nhiều hơn một return <lambda>; xuất hiện trong hàm. Điều này là do hạn chế về khấu trừ kiểu trả về là tất cả các câu lệnh trả về phải trả về các biểu thức cùng loại, nhưng mọi đối tượng lambda đều được trình biên dịch cung cấp, do đó, mỗi biểu thức có một kiểu khác nhau.

+2

C++ 14 loại suy luận nhưng bỏ qua lambdas đa hình? 'auto retFun() {return [] (tự động const & x) {return x; }; } ' – sehe

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