Lambda-opname als const-referentie?

Is het mogelijk om de referentie constvast te leggen in een lambda-expressie?

Ik wil dat de hieronder gemarkeerde opdracht mislukt, bijvoorbeeld:

#include <algorithm>
#include <string>
using namespace std;
int main()
{
    string strings[] = 
    {
        "hello",
        "world"
    };
    static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
    string best_string = "foo";
    for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
      {
        best_string = s; // this should fail
      }
    );
return 0;
}

Update:Aangezien dit een oude vraag is, is het misschien goed om deze bij te werken als er faciliteiten in C++14 zijn die hierbij helpen. Kunnen we met de extensies in C++14 een niet-const-object vastleggen door middel van const-referentie? (Augustus 2015)


Antwoord 1, autoriteit 100%

In met behulp van static_cast/ const_cast:

[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
    best_string = s; // fails
};

DEMO


In met behulp van std::as_const:

[&best_string = std::as_const(best_string)](const string& s)
{
    best_string = s; // fails
};

DEMO 2


Antwoord 2, autoriteit 83%

conststaat niet in de grammatica voor opnamen vanaf n3092:

capture:
  identifier
  & identifier
  this

De tekst vermeldt alleen capture-by-copy en capture-by-referentie en vermeldt geen enkele vorm van const-ness.

Voelt voor mij als een vergissing, maar ik heb het standaardisatieproces niet erg nauwkeurig gevolgd.


Antwoord 3, autoriteit 10%

Ik denk dat het capture-gedeelte constniet moet specificeren, omdat het capture betekent dat het alleen een manier nodig heeft om toegang te krijgen tot de buitenste scope-variabele.

De specificatie is beter gespecificeerd in de buitenste scope.

const string better_string = "XXX";
[&better_string](string s) {
    better_string = s;    // error: read-only area.
}

lambda-functieis const (kan de waarde in zijn bereik niet wijzigen), dus wanneer u variabele op waarde vastlegt, kan de variabele niet worden gewijzigd, maar de verwijzing zit niet in de lambdascoop.


Antwoord 4, autoriteit 5%

Ik denk dat als je de variabele niet als parameter van de functor gebruikt, je het toegangsniveau van de huidige functie moet gebruiken. Als je denkt dat je dat niet zou moeten doen, scheid dan je lambda van deze functie, het maakt er geen deel van uit.

Hoe dan ook, je kunt gemakkelijk hetzelfde bereiken als je wilt door in plaats daarvan een andere const-referentie te gebruiken:

#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    string strings[] = 
    {
        "hello",
        "world"
    };
    static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
    string best_string = "foo";
    const string& string_processed = best_string;
    for_each( &strings[0], &strings[num_strings], [&string_processed]  (const string& s)  -> void 
    {
        string_processed = s;    // this should fail
    }
    );
    return 0;
}

Maar dat is hetzelfde als aannemen dat je lambda moet worden geïsoleerd van de huidige functie, waardoor het een niet-lambda wordt.


Antwoord 5, autoriteit 5%

Er is een kortere weg.

Let op: er staat geen ampersand voor “best_string”.

Het zal van het type const std::reference_wrapper<T>zijn.

[best_string = std::cref(best_string)](const string& s)
{
    best_string = s; // fails
};

http://coliru.stacked-crooked.com/a/0e54d6f9441e6867


Antwoord 6, autoriteit 3%

Ik denk dat je drie verschillende opties hebt:

  • gebruik geen const-referentie, maar gebruik een kopie-opname
  • negeer het feit dat het aanpasbaar is
  • gebruik std::bind om één argument te binden van een binaire functie die een const-referentie heeft.

een kopie gebruiken

Het interessante aan lambda’s met copy captures is dat die eigenlijk alleen-lezen zijn en daarom precies doen wat je wilt.

int main() {
  int a = 5;
  [a](){ a = 7; }(); // Compiler error!
}

std::bind gebruiken

std::bindvermindert de ariteit van een functie. Houd er echter rekening mee dat dit kan/zal leiden tot een indirecte functieaanroep via een functieaanwijzer.

int main() {
  int a = 5;
  std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a);
}

Antwoord 7

Gebruik clang of wacht tot deze gcc-bug is opgelost:
bug 70385: Lambda-opname door verwijzing naar const-referentie mislukt [https://gcc. gnu.org/bugzilla/show_bug.cgi?id=70385]


Antwoord 8

Het gebruik van een const zorgt ervoor dat het algoritme ampersand de tekenreeks op zijn oorspronkelijke waarde zet,
Met andere woorden, de lambda zal zichzelf niet echt definiëren als parameter van de functie, hoewel de omringende scope een extra variabele zal hebben…
Zonder het echter te definiëren, zou het de tekenreeks niet definiëren als de typische
[&, &best_string](string const s)
Daaromis het waarschijnlijk beter als we het daarbij laten, in een poging de referentie vast te leggen.

Other episodes