Est-il possible de capturer par référence const dans une expression lambda?
Je veux que la tâche indiquée ci-dessous échoue, 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 s’agit d’une question ancienne, il serait bon de la mettre à jour s’il existe des installations en C++ 14 pour vous aider. Les extensions de C++ 14 nous permettent-elles de capturer un objet non-const par référence const? ( août 2015 )
const
n'est pas dans la grammaire pour les captures à partir de n3092:
capture:
identifier
& identifier
this
Le texte ne mentionne que capture par copie et capture par référence et ne mentionne aucune sorte de const-ness.
C'est comme un oubli, mais je n'ai pas suivi le processus de normalisation de très près.
C++ 14:
[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
best_string = s; // fails
};
C++ 17:
[&best_string = std::as_const(best_string)](const string& s)
{
best_string = s; // fails
};
Je pense que la partie capture ne doit pas spécifier const
car, en tant que moyen de capture, elle nécessite uniquement un moyen d'accéder à la variable de portée externe.
Le spécificateur est mieux spécifié dans la portée externe.
const string better_string = "XXX";
[&better_string](string s) {
better_string = s; // error: read-only area.
}
Fonction lambdaest const (ne peut pas modifier la valeur dans son étendue). Ainsi, lorsque vous capturez variable par valeur, la variable ne peut pas être modifiée, mais la référence n'est pas dans l'étendue lambda.
Je suppose que si vous n'utilisez pas la variable en tant que paramètre du foncteur, vous devez alors utiliser le niveau d'accès de la fonction actuelle. Si vous pensez que vous ne devriez pas, alors séparez votre lambda de cette fonction, il n'en fait pas partie.
Quoi qu'il en soit, vous pouvez facilement obtenir la même chose que vous voulez en utilisant une autre référence const:
#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 cela revient à supposer que votre lambda doit être isolé de la fonction actuelle, ce qui en fait un non-lambda.
Je pense que vous avez trois options différentes:
La partie intéressante à propos des lambdas avec capture de copie est que ceux-ci sont en réalité uniquement en lecture et font donc exactement ce que vous voulez.
int main() {
int a = 5;
[a](){ a = 7; }(); // Compiler error!
}
std::bind
réduit l'arité d'une fonction. Notez cependant que cela pourrait entraîner un appel de fonction indirect 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 moyen plus court.
Notez qu'il n'y a pas de perluète avant "best_string".
Ce sera du type "const std :: reference_wrapper << T >>".
[best_string = cref(best_string)](const string& s)
{
best_string = s; // fails
};
En utilisant un const, l'algorithme et commercial définiront simplement la chaîne à sa valeur initiale, .__ En d'autres termes, le lambda ne se définira pas vraiment en tant que paramètre de la fonction, bien que la portée environnante ait une variable supplémentaire ... Sans le définir cependant, il ne définirait pas la chaîne comme étant le type [&, & best_string] (string const s) Par conséquent, il est probablement préférable de le laisser si nous en restons là, en essayant de capturer la référence.
Utilisez clang ou attendez que ce bogue gcc soit corrigé: Bogue 70385: la capture lambda par référence à une référence const échoue [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]