Loại trả lại rõ ràng của Lambda


91

Khi tôi thử và biên dịch mã này (VS2010), tôi gặp lỗi sau: error C3499: a lambda that has been specified to have a void return type cannot return a value

void DataFile::removeComments()
{
  string::const_iterator start, end;
  boost::regex expression("^\\s?#");
  boost::match_results<std::string::const_iterator> what;
  boost::match_flag_type flags = boost::match_default;
  // Look for lines that either start with a hash (#)
  // or have nothing but white-space preceeding the hash symbol
  remove_if(rawLines.begin(), rawLines.end(), [&expression, &start, &end, &what, &flags](const string& line)
  {
    start = line.begin();
    end = line.end();
    bool temp = boost::regex_search(start, end, what, expression, flags);
    return temp;
  });
}

Làm cách nào để tôi chỉ định rằng lambda có kiểu trả về 'void'. Hơn nữa, làm cách nào để chỉ định lambda có kiểu trả về 'bool'?

CẬP NHẬT

Các biên dịch sau. Ai đó có thể vui lòng cho tôi biết tại sao điều đó biên dịch và người kia thì không?

void DataFile::removeComments()
{
  boost::regex expression("^(\\s+)?#");
  boost::match_results<std::string::const_iterator> what;
  boost::match_flag_type flags = boost::match_default;
  // Look for lines that either start with a hash (#)
  // or have nothing but white-space preceeding the hash symbol
  rawLines.erase(remove_if(rawLines.begin(), rawLines.end(), [&expression, &what, &flags](const string& line)
  { return boost::regex_search(line.begin(), line.end(), what, expression, flags); }));
}

6
Bạn có thể chỉ định rõ ràng nó với ->, ví dụ[&](double d) -> double { //...
Flexo

2
Tôi khuyên bạn chỉ nên nắm bắt ngầm các biến bạn cần (duy nhất [&]...), vì những gì bạn hiện có là không cần thiết phải dài dòng.
Xeo

2
[&expression, &start, &end, &what, &flags]...(của bạn) so với [&]...(của tôi). Bây giờ hãy cho tôi biết ai dài dòng hơn. ;) [&]yêu cầu lambda nắm bắt mọi thứ mà bạn sử dụng bên trong thân lambda, bằng cách tham chiếu. Nó được gọi là "mặc định chụp". Cái còn lại đang [=]và sẽ chụp bằng bản sao.
Xeo

1
@Xeo, C ++ Hiện đại Hiệu quả, Mục 31, khuyên bạn nên nắm bắt rõ ràng, để tránh các tham chiếu bị treo. Tôi đã bị cắn bởi điều đó một vài lần bản thân mình như một hình phạt cho sự lười biếng ... ờ, ngắn gọn. :-)
Emile Cormier

2
Nhân tiện, các ràng buộc được giảm bớt trên lambdas kiểu trả về được suy ra trong C ++ 14. Các kiểu trả về có thể được suy ra cho các lambdas có nhiều hơn một câu lệnh trong nội dung và miễn là biểu thức của mỗi câu lệnh trả về có cùng một kiểu, bây giờ bạn có thể có kiểu trả về được suy ra với nhiều câu lệnh trả về.
Anthony Hall

Câu trả lời:


188

Bạn có thể chỉ định rõ ràng kiểu trả về của lambda bằng cách sử dụng -> Typesau danh sách đối số:

[]() -> Type { }

Tuy nhiên, nếu lambda có một câu lệnh và câu lệnh đó là câu lệnh trả về (và nó trả về một biểu thức), trình biên dịch có thể suy ra kiểu trả về từ kiểu của một biểu thức được trả về đó. Bạn có nhiều câu lệnh trong lambda của mình, vì vậy nó không suy ra loại.


4
trình biên dịch có thể làm điều đó, nhưng tiêu chuẩn cấm trình biên dịch làm điều đó.
Johannes Schaub - litb

9
-1: Đây không phải là lỗi của trình biên dịch. Tiêu chuẩn rất rõ ràng về điều này: phần 5.1.2, đoạn 4 trình bày cách khấu trừ được thực hiện và trong những điều kiện nào.
Nicol Bolas

2
Mặc dù nó không được phép theo bản nháp mới nhất, tôi có thể thấy có vẻ như nó thực sự được cho phép trong thông số kỹ thuật cuối cùng theo nhận xét cho bản vá này gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . Bất cứ ai có thông số kỹ thuật cuối cùng để xác minh?
Eelke

2
Tôi đã sử dụng các biểu thức lambda một cách rộng rãi và chưa lần nào tôi nói rõ ràng kiểu trả về. Việc khấu trừ kiểu trả về (ít nhất là trong VS2012 & VS2013) hoạt động hoàn hảo ngay cả khi có nhiều hơn một câu lệnh trả về trong biểu thức lambda. Tất nhiên, các câu lệnh trả về khác nhau cần phải khớp trong cùng một biểu thức lambda. Ví dụ: một câu lệnh như "auto f = [] (int i) {if (i> 5) return true; return false;};" biên dịch không có vấn đề gì và nếu bạn gọi "auto b = f (10);" b sẽ thuộc loại bool và tất nhiên là đúng;
sprite

1
return nullptr;có thể ném cờ lê vào kiểu khấu trừ, mặc dù nó hợp lệ vì bất kỳ kiểu con trỏ nào cũng được trả về.
Grault

16

Kiểu trả về của lambda (trong C ++ 11) có thể được suy ra, nhưng chỉ khi có đúng một câu lệnh và câu lệnh đó là returncâu lệnh trả về một biểu thức (ví dụ: danh sách bộ khởi tạo không phải là một biểu thức). Nếu bạn có lambda nhiều câu lệnh, thì kiểu trả về được giả định là không có giá trị.

Do đó, bạn nên làm điều này:

  remove_if(rawLines.begin(), rawLines.end(), [&expression, &start, &end, &what, &flags](const string& line) -> bool
  {
    start = line.begin();
    end = line.end();
    bool temp = boost::regex_search(start, end, what, expression, flags);
    return temp;
  })

Nhưng thực sự, biểu thức thứ hai của bạn dễ đọc hơn rất nhiều.


Ví dụ tốt đẹp; nitpick: Có phải );lúc cuối cuộc gọi hàm của bạn bị thiếu không?
kevinarpe

6

Bạn có thể có nhiều câu lệnh khi vẫn trả về:

[]() -> your_type {return (
        your_statement,
        even_more_statement = just_add_comma,
        return_value);}

http://www.cplusplus.com/doc/tutorial/operators/#comma


4
dấu phẩy là một toán tử quay vòng. nó gây nhầm lẫn cho những người không biết về sự tồn tại hoặc mức độ ưu tiên của nó. không bao giờ sử dụng hợp lệ cả imo. nó luôn luôn có thể tránh được với nhiều chức năng hơn hoặc mã được tổ chức tốt hơn.
jheriko

@jheriko đồng ý, sự tồn tại của câu trả lời của tôi chỉ dành cho những người thực sự muốn có giải pháp một lớp độc lập XD (nó vẫn là một dòng, phải không?). Dấu phẩy thực sự không đáng chú ý, và không ai có thể đặt toàn bộ phương thức chính ở dạng này.
Valen

1
chắc chắn, bạn chắc chắn đang đưa ra một câu trả lời hợp lệ, tôi chỉ không phải là người thích làm bất cứ điều gì để khuyến khích hoặc thậm chí chứng minh việc thực hành xấu. một khi mọi người biết rằng dấu phẩy là một toán tử, nó sẽ đếm ngược cho đến khi họ bắt đầu lạm dụng nó và một dấu phẩy dài hơn cho đến khi họ học tốt hơn. :)
jheriko

@jheriko Tôi đã thấy nó được sử dụng thú vị trong danh sách khởi tạo thành viên một lần, nhưng đó chỉ là để lộn xộn, nếu tôi nhớ không nhầm.
Justin Time - Phục hồi Monica
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.