2016-07-27 21 views
20

Nói rằng tôi có biến sau đây có chứa một lambda:C++ 11 Thay đổi `auto` Lambda thành Lambda khác?

auto a = [] { return true; }; 

Và tôi muốn a trở false sau này. Tôi có thể làm điều gì đó dọc theo dòng này không?

a = [] { return false; }; 

Cú pháp này mang lại cho tôi những lỗi sau đây:

binary '=' : no operator found which takes a right-hand operand of type 
'main::<lambda_a7185966f92d197a64e4878ceff8af4a>' (or there is no acceptable conversion) 

IntelliSense: no operator "=" matches these operands 
     operand types are: lambda []bool()->bool = lambda []bool()->bool 

Có cách nào để đạt được một cái gì đó như thế này? Tôi muốn thay đổi biến số auto thành một lambda khác. Tôi chủ yếu là người mới bắt đầu nên tôi có thể thiếu một số kiến ​​thức về auto hoặc lambdas. Cảm ơn.

+2

Có 'bool b = true; auto a = [& b] {return b; }; b = false; 'giải pháp nhưng điều này tất nhiên không tổng quát cho tất cả các tình huống. – MSalters

Trả lời

31

Mỗi biểu thức lambda tạo ra một kiểu duy nhất mới, do đó loại lambda đầu tiên của bạn khác với loại thứ hai của bạn (example). Ngoài ra, toán tử gán bản sao của một lambda được định nghĩa là đã xóa (example), do đó bạn không thể làm điều này gấp đôi. Đối với một hiệu ứng tương tự, bạn có thể có a là một đối tượng std::function mặc dù nó sẽ chi phí bạn một số hiệu suất

std::function<bool()> a = [] { return true; }; 
a = [] { return false; }; 
32

Một Lambda có thể được chuyển đổi sang một con trỏ hàm sử dụng toán tử unary + như vậy:

+[]{return true;} 

miễn là nhóm chụp trống và không có đối số auto.

Nếu bạn làm điều này, bạn có thể gán các lambdas khác nhau cho cùng một biến miễn là các lambdas đều có cùng chữ ký.

Trong trường hợp của bạn,

Live example on Coliru

sẽ cả biên dịch và hành động như bạn mong đợi. Bạn có thể sử dụng các con trỏ hàm theo cách giống như bạn mong đợi để sử dụng một lambda, vì cả hai sẽ hoạt động như functors.


1. Trong C++ 14, bạn có thể khai lambdas với auto như các loại tham số, như [](auto t){}. Đây là generic lambdas và có một tem operator(). Vì một con trỏ hàm không thể đại diện cho một hàm templated, thủ thuật + sẽ không hoạt động với các lambdas chung.

2. Về mặt kỹ thuật, bạn không cần toán tử thứ hai + trên nhiệm vụ. Lambda sẽ chuyển đổi thành kiểu con trỏ hàm khi gán. Tôi thích sự nhất quán, mặc dù.

+10

Khoảnh khắc khi C++ chính thức bước vào vương quốc Perl! – peppe

+0

@jaggedSpire Tôi cần điều này rất nhiều lần, và tôi nghĩ giải pháp duy nhất là các câu trả lời 'hàm' khác cho câu hỏi này. Làm thế nào bạn tìm hiểu về điều này? Tôi chưa bao giờ thấy nó trước đây. –

+0

@JonathanMee Tôi thực sự tìm thấy nó từ sau một liên kết có liên quan trong thanh bên, ngày xửa ngày xưa: [Một lambda tích cực: '+ [] {}' - Điều gì là phép thuật này?] (Http://stackoverflow.com/questions/18889028) – jaggedSpire

4

Mỗi lambda có một loại khác nhau, do đó bạn không thể thay đổi nó. Bạn có thể sử dụng một số std::function để giữ một đối tượng có thể gọi tùy ý, có thể được thay đổi theo ý muốn.

std::function <bool()> a = [] { return true; }; 
a = [] { return false; }; 
+0

Tôi đoán Ryan đã đánh bại bạn với nó khi đăng cùng một thứ. Nhưng bạn đang thiếu dấu chấm phẩy. –

1

Chúng tôi có thể sử dụng để chuyển đổi retrospective call lambda để std :: chức năng:

template<typename T> 
struct memfun_type 
{ 
    using type = void; 
}; 

template<typename Ret, typename Class, typename... Args> 
struct memfun_type<Ret(Class::*)(Args...) const> 
{ 
    using type = std::function<Ret(Args...)>; 
}; 

template<typename F> 
typename memfun_type<decltype(&F::operator())>::type 
FFL(F const &func) 
{ // Function from lambda ! 
    return func; 
} 

Sau đó chúng tôi sẽ có thể làm (kể từ 'a' là std :: loại chức năng bây giờ):

auto a = FFL([] { return false; }); 
a = FFL([] { return true; }); 
+0

Một chút giải thích sẽ tốt đẹp hơn. –

0

C++17 bạn có thể có tham số mẫu std::function được suy luận nhờ Class template argument deduction. Nó thậm chí hoạt động với chụp lambdas:

int a = 24; 

std::function f = [&a] (int p) { return p + a; }; 
f    = [&a] (int p) { return p - a; }; 
f    = [] (int p) { return p; }; 

Điều này có ích với chữ ký phức tạp hơn và thậm chí nhiều hơn với các loại trả về suy luận.

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