Question

Est-il possible de capture par référence const dans une expression lambda?

Je veux l'affectation marquée ci-dessous à l'échec, par exemple:

#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";

    for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
      {
        best_string = s; // this should fail
      }
    );
    return 0;
}

Mise à jour: Comme il est une vieille question, il pourrait être bon de mettre à jour s'il y a des installations en C ++ 14 aider. Faites les extensions en C ++ 14 nous permettent de capturer un objet non-const par référence const? ( Août ici à 2015 )

Était-ce utile?

La solution

const n'est pas dans la grammaire des captures comme des n3092:

capture:
  identifier
  & identifier
  this

Le texte ne mentionne la capture par copie et la capture par référence et ne mentionne aucune sorte de const-ness.

Sentir comme un oubli de moi, mais je n'ai pas suivi le processus de normalisation de très près.

Autres conseils

C ++ 14:

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

DEMO


C ++ 17:

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

DEMO 2

Je pense que la partie de capture ne devrait pas préciser const, comme les moyens de capture, mais seulement un moyen d'accéder à la variable de portée externe.

Le spécificateur est mieux spécifié dans le champ d'application externe.

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

fonction lambda est const (ne peut pas valeur de changement dans son champ d'application), la variable ne peut donc quand vous variable de capture en valeur, être modifiée, mais la référence n'est pas dans le champ d'application lambda.

Je suppose que si vous n'êtes pas en utilisant la variable en tant que paramètre du foncteur, alors vous devriez utiliser le niveau d'accès de la fonction actuelle. Si vous pensez que vous ne devriez pas, puis séparer votre lambda de cette fonction, il ne fait pas partie de celui-ci.

De toute façon, vous pouvez facilement obtenir la même chose que vous voulez en utilisant une autre référence const au lieu:

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

Mais ce qui est le même que celui en supposant que votre lambda ont à isoler de la fonction en cours, ce qui en fait un non-lambda.

Je pense que vous avez trois options:

  • ne pas utiliser la référence const, mais utiliser une capture de copie
  • ignorer le fait qu'il est modifiable
  • utiliser std :: se lient à une liaison argument d'une fonction binaire qui comporte une référence de const.

en utilisant une copie

La partie intéressante sur lambdas avec des captures de copie est que ceux-ci sont effectivement lus seulement et donc faire exactement ce que vous voulez.

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

en utilisant std :: bind

std::bind réduit la arité d'une fonction. Notez cependant que cela pourrait / conduira à un appel de fonction indirecte via un pointeur de fonction.

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

Il y a un chemin plus court.

Notez qu'il n'y a pas esperluette avant "best_string".

Il sera d'un type "const std :: reference_wrapper << T >>".

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

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

Utilisez clang ou attendre jusqu'à ce que ce bug gcc est fixé: bug 70385: capture Lambda par référence de référence const échoue [ https: // gcc. gnu.org/bugzilla/show_bug.cgi?id=70385 ]

L'utilisation d'un const devra simplement l'algorithme esperluette définir la chaîne à sa valeur d'origine, En d'autres termes, le lambda ne sera pas vraiment se définir comme paramètre de la fonction, bien que la portée environnante aura une variable supplémentaire ... Sans définir cependant, il ne définirait pas la chaîne comme typique   [&, & best_string] (const string s) Par conséquent , il est plus probable mieux si nous laissons simplement à cela, en essayant de saisir la référence.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top