2011-10-10 36 views
37
#include <vector> 
#include <algorithm> 

void foo(int) 
{ 
} 

int main() 
{ 
    std::vector<int> v({ 1,2,3 }); 

    std::for_each(v.begin(), v.end(), [](auto it) { foo(it+5); }); 
} 

Khi biên soạn, ví dụ trên bắt đầu ra lỗi như thế này:Sử dụng auto trong một hàm lambda

h4.cpp: In function 'int main()': 
h4.cpp:13:47: error: parameter declared 'auto' 
h4.cpp: In lambda function: 
h4.cpp:13:59: error: 'it' was not declared in this scope 

Liệu nó có nghĩa là từ khóa auto không nên được sử dụng trong các biểu thức lambda?

này hoạt động:

std::for_each(v.begin(), v.end(), [](int it) { foo(it+5); }); 

Tại sao phiên bản với từ khóa tự động không hoạt động?

+1

Tôi nghĩ rằng ngay cả khi nó là một lambda, nó vẫn làm việc như một chức năng, và phải có chữ ký. Với tính năng tự động bạn cho phép trình biên dịch quyết định loại, vì vậy lambda của bạn không có chữ ký thực cho đến khi biên dịch. – Geoffroy

+3

Chúng tôi thực sự cần lambdas đa hình (mẫu ẩn AKA) trong tiêu chuẩn tiếp theo. Câu hỏi này chỉ là một trong nhiều trường hợp mà mọi người chỉ cho rằng 'auto' hoạt động theo cách này. Tôi thấy không có lý do nó không nên. –

+0

deft_code, tôi ở bên bạn.Nó là một trường hợp sử dụng hợp lý cho tự động. – Robert

Trả lời

63

từ khóa tự động không hoạt động như một loại đối số chức năng. Nếu bạn không muốn sử dụng loại thực tế trong các hàm lambda, thì bạn có thể sử dụng mã bên dưới.

for_each(begin(v), end(v), [](decltype(*begin(v)) it){ 
     foo(it + 5);   
}); 
+37

Chúng tôi sẽ nhận hỗ trợ 'auto' trong lambdas trong [C++ 14] (http://en.wikipedia.org/wiki/C%2B%2B14#Generic_lambdas). –

+0

Tâm trí ngôi sao trước 'bắt đầu (v)' trong 'decltype'. Bạn muốn loại giá trị không phải là loại trình vòng lặp. (thông báo lỗi khi bạn thất bại sẽ là bí ẩn). –

4

Loại lambda cần được biết trước khi trình biên dịch có thể khởi tạo std::for_each. Mặt khác, ngay cả khi nó về lý thuyết có thể, rằng auto chỉ có thể được suy ra sau khi for_each được khởi tạo bằng cách xem cách hàm functor được gọi.

Nếu có thể, hãy quên về for_each, và sử dụng nhiều có trụ sở tại vòng đó là đơn giản hơn rất nhiều:

for (int it : v) { 
    foo(it + 5); 
} 

này cũng nên đối phó độc đáo với auto (và auto&const auto&).

for (auto it : v) { 
    foo(it + 5); 
} 
+0

Có nhưng chỉ hoạt động với for_each, chứ không phải các thuật toán khác. ví dụ. bạn muốn sắp xếp trên một lambda. – CashCow

20

Điều này đã được thảo luận ngắn gọn bởi Herb Sutter trong một cuộc phỏng vấn. nhu cầu của bạn cho auto lập luận là trong thực tế không khác đòi hỏi chức năng bất kỳ nên declarable với auto, như thế này:

auto add(auto a, auto b) -> decltype(a + b) { return a + b; } 

Tuy nhiên, lưu ý rằng đây không phải là thực sự là một chức năng nào cả, mà đúng hơn là nó một mẫu chức năng, giống như:

template <typename S, typename T> 
auto add(S a, T b) -> decltype(a + b) { return a + b; } 

vì vậy, về cơ bản bạn đang yêu cầu cho một cơ sở để biến bất kỳ chức năng vào một mẫu bằng cách thay đổi đối số của nó. Vì các mẫu là một loại thực thể rất khác nhau trong hệ thống kiểu của C++ (nghĩ về tất cả các quy tắc đặc biệt cho các mẫu, như tra cứu và khấu trừ hai giai đoạn), đây sẽ là thay đổi thiết kế cấp tiến với các nhánh không lường trước được. sẽ sớm có mặt trong tiêu chuẩn.

+1

Không, không hỏi hoặc yêu cầu :) Tôi chỉ tự hỏi tại sao nó không hoạt động. –

+5

Vâng, đó là cơ bản lý do tương tự như cho "tại sao không phải tất cả các mẫu chức năng" - nó chỉ không phù hợp với thiết kế của ngôn ngữ. –

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