Jenis Pengembalian Eksplisit dari Lambda

93

Ketika saya mencoba dan mengkompilasi kode ini (VS2010) saya mendapatkan kesalahan berikut: 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;
  });
}

Bagaimana saya menentukan bahwa lambda memiliki tipe pengembalian 'void'. Terlebih lagi, bagaimana cara menentukan bahwa lambda memiliki tipe kembalian 'bool'?

MEMPERBARUI

Kompilasi berikut. Bisakah seseorang memberi tahu saya mengapa yang terkompilasi dan yang lainnya tidak?

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); }));
}
Ryan
sumber
6
Anda dapat secara eksplisit menentukannya dengan ->, misalnya[&](double d) -> double { //...
Flexo
2
Saya menyarankan Anda untuk secara implisit menangkap variabel yang Anda butuhkan (hanya [&]...), karena apa yang Anda miliki saat ini tidak perlu bertele-tele.
Xeo
2
[&expression, &start, &end, &what, &flags]...(milikmu) vs [&]...(milikku). Sekarang beri tahu saya siapa yang lebih bertele-tele. ;) [&]memberi tahu lambda untuk menangkap semua yang Anda gunakan di dalam tubuh lambda, dengan referensi. Ini disebut "capture default". Yang lainnya adalah [=]dan akan ditangkap dengan salinan.
Xeo
1
@Xeo, Effective Modern C ++, Item 31, merekomendasikan pengambilan secara eksplisit, untuk menghindari referensi yang menggantung. Saya sendiri telah digigit oleh itu beberapa kali sebagai hukuman karena malas ... er, ringkas. :-)
Emile Cormier
2
Ngomong-ngomong, batasan dikurangi pada lambda tipe kembali yang disimpulkan di C ++ 14. Tipe pengembalian dapat disimpulkan untuk lambda dengan lebih dari satu pernyataan dalam isi, dan selama ekspresi setiap pernyataan pengembalian memiliki tipe yang sama, Anda sekarang dapat memiliki tipe pengembalian simpulan dengan beberapa pernyataan pengembalian.
Anthony Hall

Jawaban:

194

Anda bisa secara eksplisit menentukan tipe kembalian lambda dengan menggunakan -> Typesetelah daftar argumen:

[]() -> Type { }

Namun, jika lambda memiliki satu pernyataan dan pernyataan itu adalah pernyataan kembali (dan mengembalikan ekspresi), kompilator bisa menyimpulkan tipe pengembalian dari tipe satu ekspresi yang dikembalikan. Anda memiliki banyak pernyataan di lambda Anda, jadi itu tidak menyimpulkan jenisnya.

Seth Carnegie
sumber
4
kompilator dapat melakukan itu, tetapi standar melarangnya untuk melakukan itu.
Johannes Schaub - litb
10
-1: Ini bukan bug kompilator. Standar tersebut sangat jelas dalam hal ini: bagian 5.1.2, paragraf 4 menjelaskan bagaimana pemotongan dibuat dan dalam kondisi apa pemotongan tersebut.
Nicol Bolas
2
Meskipun tidak diizinkan menurut draf terbaru, saya dapat menemukan sepertinya itu benar-benar diizinkan dalam spesifikasi akhir melalui komentar untuk patch ini gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . Ada yang punya spesifikasi akhir untuk diverifikasi?
Eelke
2
Saya telah menggunakan ekspresi lambda secara ekstensif dan tidak sekali pun saya secara eksplisit menyatakan tipe pengembalian. Pengurangan jenis pengembalian (setidaknya di bawah VS2012 & VS2013) bekerja dengan sempurna bahkan jika ada lebih dari satu pernyataan pengembalian dalam ekspresi lambda. Tentu saja, berbagai pernyataan pengembalian harus cocok dalam ekspresi lambda yang sama. Misalnya pernyataan seperti "auto f = [] (int i) {if (i> 5) return true; return false;};" mengkompilasi tanpa masalah dan jika Anda memanggil "auto b = f (10);" b akan menjadi tipe bool dan tentu saja benar;
sprite
1
return nullptr;dapat melempar kunci pas dalam pengurang jenis, meskipun itu valid sebagai jenis penunjuk apa pun yang dikembalikan.
Grault
16

Jenis kembalian lambda (dalam C ++ 11) dapat disimpulkan, tetapi hanya jika ada tepat satu pernyataan, dan pernyataan itu adalahreturn pernyataan yang mengembalikan ekspresi (misalnya, daftar penginisialisasi bukan ekspresi). Jika Anda memiliki lambda multi-pernyataan, maka jenis kembalian diasumsikan tidak berlaku.

Karena itu, Anda harus melakukan ini:

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

Tapi sungguh, ekspresi keduamu jauh lebih mudah dibaca.

Nicol Bolas
sumber
Contoh yang bagus; nitpick: Apakah panggilan fungsi Anda hilang );di akhir?
kevinarpe
6

Anda dapat memiliki lebih dari satu pernyataan saat masih mengembalikan:

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

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

Valen
sumber
4
koma adalah operator yang memberontak. itu membingungkan orang-orang yang tidak menyadari keberadaannya atau tingkat prioritasnya. tidak pernah ada penggunaan yang valid baik imo. itu selalu dapat dihindari dengan lebih banyak fungsi atau kode yang terorganisir dengan lebih baik.
jheriko
@jheriko setuju, keberadaan jawaban saya hanya untuk yang benar-benar menginginkan solusi XD satu baris mandiri (masih satu baris ya?). Koma benar-benar tidak terlihat, dan tidak ada yang akan meletakkan seluruh metode utama dalam formulir ini.
Valen
1
Tentu, Anda pasti memberikan jawaban yang valid, saya hanya bukan penggemar yang pernah melakukan sesuatu untuk mendorong atau bahkan menunjukkan praktik buruk. sekali orang mengetahui bahwa koma adalah operator, itu menghitung mundur sampai mereka mulai menyalahgunakannya dan yang lebih lama sampai mereka belajar lebih baik. :)
jheriko
@jheriko Saya pernah melihatnya digunakan dalam daftar inisialisasi anggota sekali, tapi itu hanya untuk main-main, jika saya ingat dengan benar.
Waktu Justin - Kembalikan Monica