Explicit Return Type ของ Lambda


94

เมื่อฉันพยายามรวบรวมรหัสนี้ (VS2010) ฉันได้รับข้อผิดพลาดต่อไปนี้: 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;
  });
}

ฉันระบุได้อย่างไรว่าแลมบ์ดามีประเภทการส่งคืน 'โมฆะ' ยิ่งไปกว่านั้นฉันจะระบุได้อย่างไรว่าแลมบ์ดามีประเภทการส่งคืน 'บูล'

อัปเดต

คอมไพล์ต่อไปนี้ ใครช่วยบอกหน่อยได้ไหมว่าทำไมคอมไพล์นั้นและอีกอันไม่ได้?

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
คุณสามารถระบุอย่างชัดเจนด้วย->เช่น[&](double d) -> double { //...
Flexo

2
ฉันขอแนะนำให้คุณจับตัวแปรที่คุณต้องการโดยปริยาย (เท่านั้น[&]...) เนื่องจากสิ่งที่คุณมีอยู่ในปัจจุบันนั้นไม่จำเป็น
Xeo

2
[&expression, &start, &end, &what, &flags]...(ของคุณ) กับ[&]...(ของฉัน) ตอนนี้บอกฉันว่าใครละเอียดกว่ากัน ;) [&]บอกให้แลมบ์ดาจับทุกอย่างที่คุณใช้ภายในร่างกายแลมด้าโดยอ้างอิง เรียกว่า "ค่าเริ่มต้นการบันทึก" อีกอันคือ[=]และจะจับโดยสำเนา
Xeo

1
@Xeo, C ++ สมัยใหม่ที่มีประสิทธิภาพ, รายการที่ 31 แนะนำให้จับภาพอย่างชัดเจนเพื่อหลีกเลี่ยงการอ้างอิงที่ห้อยลง ฉันเคยถูกกัดมาแล้วสองสามครั้งเพื่อเป็นการลงโทษที่ขี้เกียจ ... เอ้อรัดกุม :-)
Emile Cormier

2
อย่างไรก็ตามข้อ จำกัด จะลดลงใน lambdas ชนิดส่งคืนที่อนุมานใน C ++ 14 ประเภทผลตอบแทนสามารถอนุมานได้สำหรับ lambdas ที่มีคำสั่งมากกว่าหนึ่งรายการในเนื้อความและตราบใดที่นิพจน์ของคำสั่งส่งคืนแต่ละรายการมีประเภทเดียวกันตอนนี้คุณสามารถมีประเภทผลตอบแทนที่อนุมานได้โดยมีคำสั่งส่งคืนหลายรายการ
Anthony Hall

คำตอบ:


195

คุณสามารถระบุประเภทการส่งคืนของแลมบ์ดาอย่างชัดเจนโดยใช้-> Typeหลังรายการอาร์กิวเมนต์:

[]() -> Type { }

อย่างไรก็ตามหากแลมบ์ดามีคำสั่งเดียวและคำสั่งนั้นเป็นคำสั่งส่งคืน (และส่งคืนนิพจน์) คอมไพลเลอร์สามารถอนุมานประเภทการส่งคืนจากชนิดของนิพจน์ที่ส่งคืน คุณมีหลายข้อความในแลมบ์ดาของคุณดังนั้นจึงไม่ได้อนุมานประเภท


4
คอมไพเลอร์สามารถทำได้ แต่มาตรฐานห้ามไม่ให้ทำเช่นนั้น
Johannes Schaub - litb

10
-1: นี่ไม่ใช่บั๊กของคอมไพเลอร์ มาตรฐานมีความชัดเจนในเรื่องนี้: ส่วน 5.1.2 วรรค 4 ระบุวิธีการหักเงินและภายใต้เงื่อนไขที่เป็นอยู่
Nicol Bolas

2
แม้ว่าจะไม่ได้รับอนุญาตตามร่างล่าสุดฉันพบว่ามันได้รับอนุญาตจริงในข้อกำหนดขั้นสุดท้ายตามความคิดเห็นสำหรับแพทช์นี้gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . ใครมีข้อมูลจำเพาะสุดท้ายที่จะตรวจสอบ?
Eelke

2
ฉันใช้นิพจน์แลมบ์ดาอย่างกว้างขวางและไม่เคยระบุประเภทการส่งคืนอย่างชัดเจนสักครั้ง การหักประเภทผลตอบแทน (อย่างน้อยภายใต้ VS2012 & VS2013) ทำงานได้อย่างไม่มีที่ติแม้ว่าจะมีคำสั่ง return มากกว่าหนึ่งคำในนิพจน์ lambda แน่นอนว่าคำสั่งส่งคืนต่างๆต้องตรงกันภายในนิพจน์แลมบ์ดาเดียวกัน เช่นคำสั่งเช่น "auto f = [] (int i) {if (i> 5) return true; return false;};" รวบรวมได้โดยไม่มีปัญหาและหากคุณเรียก "auto b = f (10);" b จะเป็นประเภทบูลและแน่นอนว่าเป็นจริง
สไปรต์

1
return nullptr;สามารถโยนประแจในประเภทการหักแม้ว่าจะถูกต้องเป็นประเภทของตัวชี้ก็ตาม
Grault

16

ประเภทการกลับมาของแลมบ์ดา (ใน C ++ 11) สามารถอนุมานได้ แต่เฉพาะเมื่อมีคำสั่งว่าหนึ่งและคำสั่งที่เป็นreturnคำสั่งที่ผลตอบแทนการแสดงออก (รายการ initializer ไม่แสดงออกเช่น) หากคุณมีแลมด้าแบบหลายคำสั่งประเภทการส่งคืนจะถือว่าเป็นโมฆะ

ดังนั้นคุณควรทำสิ่งนี้:

  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;
  })

แต่จริงๆแล้วสำนวนที่สองของคุณอ่านได้ง่ายกว่ามาก


ตัวอย่างที่ดี; nitpick: การเรียกฟังก์ชันของคุณขาดหายไป);ในตอนท้ายหรือไม่?
kevinarpe

6

คุณสามารถมีมากกว่าหนึ่งคำสั่งเมื่อยังคงส่งคืน:

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

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


4
ลูกน้ำเป็นตัวดำเนินการที่น่ารังเกียจ สร้างความสับสนให้กับผู้คนที่ไม่ทราบถึงการดำรงอยู่หรือระดับความสำคัญ ไม่มีการใช้ imo ที่ถูกต้อง สามารถหลีกเลี่ยงได้ด้วยฟังก์ชันที่มากขึ้นหรือโค้ดที่มีการจัดระเบียบที่ดีขึ้น
jheriko

@jheriko เห็นด้วยการมีอยู่ของคำตอบของฉันมีไว้สำหรับผู้ที่ต้องการโซลูชัน XD แบบซับเดียวที่เป็นอิสระเท่านั้น (ยังคงเป็นบรรทัดเดียวใช่ไหม) ลูกน้ำไม่สามารถสังเกตเห็นได้และไม่มีใครเคยใส่วิธีการหลักทั้งหมดในแบบฟอร์มนี้
Valen

1
แน่นอนว่าคุณกำลังให้คำตอบที่ถูกต้องอย่างแน่นอนฉันไม่ใช่แฟนคลับที่เคยทำอะไรเพื่อส่งเสริมหรือแสดงให้เห็นถึงการปฏิบัติที่ไม่ดี เมื่อผู้คนรู้ว่าลูกน้ำเป็นตัวดำเนินการมันจะนับถอยหลังจนกว่าพวกเขาจะเริ่มใช้ในทางที่ผิดและอีกต่อไปจนกว่าพวกเขาจะเรียนรู้ได้ดีขึ้น :)
jheriko

@jheriko ฉันเคยเห็นมันมีการใช้งานที่น่าสนใจในรายการเริ่มต้นของสมาชิกครั้งหนึ่ง แต่นั่นเป็นเพียงการล้อเล่นถ้าฉันจำไม่ผิด
เวลาจัสติน - คืนสถานะโมนิกา
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.