Lambda'nın Açık Dönüş Tipi


94

Bu kodu (VS2010) denediğimde ve derlediğimde aşağıdaki hatayı alıyorum: 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;
  });
}

Lambda'nın 'void' dönüş türüne sahip olduğunu nasıl belirttim? Dahası, lambda'nın 'bool' dönüş türüne sahip olduğunu nasıl belirtebilirim?

GÜNCELLEME

Aşağıdaki derlemeler. Birisi bana bunun neden derlendiğini ve diğerinin neden olmadığını söyleyebilir mi?

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
Bunu açıkça belirtebilirsiniz ->, örneğin[&](double d) -> double { //...
Flexo

2
[&]...Şu anda sahip olduğunuz şey gereksiz bir şekilde ayrıntılı olduğundan, yalnızca ihtiyacınız olan değişkenleri (yalnızca ) örtük olarak yakalamanızı tavsiye ederim .
Xeo

2
[&expression, &start, &end, &what, &flags]...(senin) vs [&]...(benim). Şimdi bana kimin daha ayrıntılı olduğunu söyle. ;) [&]lambda'ya lambda gövdesi içinde kullandığınız her şeyi referans alarak yakalamasını söyler. Buna "varsayılan yakalama" denir. Diğeri ise [=]kopya ile yakalanacak.
Xeo

1
@Xeo, Etkili Modern C ++, Öğe 31, referansların sarkmasını önlemek için açıkça yakalama yapılmasını önerir. Lazım olduğum için bir kaç kez ceza olarak ısırıldım ... şey, özlü. :-)
Emile Cormier

2
Bu arada, kısıtlamalar C ++ 14'te çıkarılan dönüş tipi lambdalarda azaltılır. Gövdede birden fazla ifadeye sahip lambdalar için dönüş türleri çıkarılabilir ve her return ifadesinin ifadesi aynı türe sahip olduğu sürece, artık birden çok dönüş ifadesine sahip çıkarılmış bir dönüş türüne sahip olabilirsiniz.
Anthony Hall

Yanıtlar:


195

-> TypeBağımsız değişkenler listesinden sonra kullanarak bir lambda'nın dönüş türünü açıkça belirtebilirsiniz :

[]() -> Type { }

Ancak, bir lambda'nın bir ifadesi varsa ve bu ifade bir dönüş ifadesiyse (ve bir ifade döndürürse), derleyici dönüş türünü döndürülen ifadenin türünden çıkarabilir. Lambda'nızda birden fazla ifade var, bu yüzden türü çıkarmaz.


4
derleyici bunu yapabilir, ancak standart bunu yapmasını yasaklar.
Johannes Schaub - litb

10
-1: Bu bir derleyici hatası değildir. Standart bu konuda çok açıktır: Bölüm 5.1.2, paragraf 4, kesintinin nasıl ve hangi koşullar altında yapıldığını açıklamaktadır.
Nicol Bolas

2
En son taslağa göre buna izin verilmese de, bu yama için yapılan yorum gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html tarafından yapılan nihai spesifikasyonlarda buna gerçekten izin verildiği görülüyor. . Doğrulamak için son spesifikasyona sahip olan var mı?
Eelke

2
Lambda ifadelerini yoğun bir şekilde kullandım ve bir kez bile dönüş türünü açıkça belirtmedim. Dönüş türünün kesintisi (en azından VS2012 ve VS2013 altında), lambda ifadesinde birden fazla dönüş ifadesi olsa bile kusursuz çalışır. Elbette, çeşitli dönüş ifadelerinin aynı lambda ifadesi içinde eşleşmesi gerekir. Örneğin, "auto f = [] (int i) {if (i> 5) doğru döndür; yanlış döndür;};" sorunsuz derler ve "auto b = f (10)" olarak adlandırırsanız; b türü bool olacak ve tabii ki doğru olacaktır;
sprite

1
return nullptr;aksi takdirde döndürülen işaretçi türü ne olursa olsun geçerli olsa bile, tür kesintisine bir anahtar atabilir.
Grault

16

Bir lambda'nın dönüş türü (C ++ 11'de) çıkarılabilir, ancak yalnızca tam olarak bir ifade olduğunda ve bu ifade returnbir ifade döndüren bir ifadedir (örneğin, başlatıcı listesi bir ifade değildir). Çok ifadeli bir lambda'nız varsa, dönüş türünün geçersiz olduğu varsayılır.

Bu nedenle, şunu yapmalısınız:

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

Ama gerçekten, ikinci ifadeniz çok daha okunabilir.


Güzel örnek; nitpick: İşlev çağrınız );sonunda eksik mi?
kevinarpe

6

Hala döndüğünüzde birden fazla ifadeye sahip olabilirsiniz:

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

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


4
virgül iğrenç bir operatördür. Varlığının veya öncelik seviyesinin farkında olmayan insanların kafasını karıştırır. hiçbir zaman geçerli bir imo kullanımı yoktur. her zaman daha fazla işlevle veya daha iyi organize edilmiş kodlarla önlenebilir.
jheriko

@jheriko katılıyorum, cevabımın varlığı yalnızca gerçekten bağımsız bir tek satırlık çözüm XD isteyenler içindir (hala tek satır, değil mi?). Virgül gerçekten fark edilmiyor ve hiç kimse tüm ana yöntemi bu forma koymaz.
Valen

1
elbette, kesinlikle geçerli bir cevap veriyorsunuz, ben sadece kötü uygulamaları teşvik etmek ve hatta göstermek için hiçbir şey yapmanın hayranı değilim. İnsanlar virgülün bir operatör olduğunu öğrendikten sonra, onu kötüye kullanmaya başlayana kadar bir geri sayım ve daha iyi öğrenene kadar daha uzun bir süre. :)
jheriko

@jheriko Bir zamanlar bir üye başlatma listesinde ilginç bir şekilde kullanıldığını gördüm, ancak doğru hatırlıyorsam bu sadece etrafta dolaşmak içindi.
Justin Time - Monica'yı yeniden
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.