Est-il possible de capturer par référence const dans une expression lambda?
Je souhaite que le devoir indiqué 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 vieille question, il pourrait être bon de la mettre à jour s'il existe des fonctionnalités dans C ++ 14 pour vous aider. Les extensions en C ++ 14 nous permettent-elles de capturer un objet non const par référence const? ( Août 2015 )
[&, &best_string](string const s) { ...}
:?Réponses:
const
n'est pas dans la grammaire des captures à partir de n3092:Le texte ne mentionne que la capture par copie et la capture par référence et ne mentionne aucune sorte de const-ness.
Cela me semble un oubli, mais je n'ai pas suivi de très près le processus de normalisation.
la source
const
. Ou plus correctement, si la variable de capture étaitconst
, le compilateur aurait imposé le comportement correct au programmeur. Ce serait bien si la syntaxe était prise en charge[&mutableVar, const &constVar]
.a
tant queconst
, déclarezconst auto &b = a;
avant le lambda et capturezb
[&foo = this->foo]
intérieur d'uneconst
fonction me donne une erreur indiquant que la capture elle-même rejette les qualificatifs. Cela pourrait être un bogue dans GCC 5.1, cependant, je suppose.Dans c ++ 14en utilisant
static_cast
/const_cast
:DEMO
Dans c ++ 17utilisant
std::as_const
:DÉMO 2
la source
const_cast
peut changer sans condition un objet volatil en un objet const (lorsqu'on lui demande de le convertirconst
), ainsi, pour ajouter des contraintes que je préfèrestatic_cast
static_cast
référence à const peut créer silencieusement un temporaire si vous n'avez pas obtenu le type exactement&basic_string = std::as_const(best_string)
devrait résoudre tous les problèmesconst& best_string
.Je pense que la partie de capture ne devrait pas spécifier
const
, comme moyen de capture, il suffit d'un moyen d'accéder à la variable de portée externe.Le spécificateur est mieux spécifié dans la portée externe.
La fonction lambda est const (ne peut pas changer la valeur dans sa portée), donc lorsque vous capturez une variable par valeur, la variable ne peut pas être modifiée, mais la référence n'est pas dans la portée lambda.
la source
better_string
dans la portée contenant, cette solution ne fonctionnera pas. Le cas d'utilisation de la capture en tant que const-ref est lorsque la variable doit être mutable dans la portée contenant mais pas dans le lambda.const string &c_better_string = better_string;
et le passer avec plaisir au lambda:[&c_better_string]
Je suppose que si vous n'utilisez pas la variable comme paramètre du foncteur, vous devriez 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, cela 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 à la place:
Mais c'est la même chose que de supposer que votre lambda doit être isolé de la fonction actuelle, ce qui en fait un non-lambda.
la source
best_string
que. En dehors de cela, GCC 4.5 "rejette avec succès" le code comme prévu.Je pense que vous avez trois options différentes:
en utilisant une copie
La partie intéressante à propos des lambdas avec des captures de copie est que celles-ci sont en réalité en lecture seule et font donc exactement ce que vous voulez.
en utilisant std :: bind
std::bind
réduit l'arité d'une fonction. Notez cependant que cela pourrait / conduira à un appel de fonction indirect via un pointeur de fonction.la source
Il existe un moyen plus court.
Notez qu'il n'y a pas d'esperluette avant "best_string".
Il sera de type "const std :: reference_wrapper << T >>".
http://coliru.stacked-crooked.com/a/0e54d6f9441e6867
la source
Utilisez clang ou attendez que ce bogue gcc soit corrigé: bogue 70385: La capture Lambda par référence à la référence const échoue [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]
la source
L'utilisation d'un const aura simplement l'esperluette de l'algorithme et définira la chaîne sur sa valeur d'origine.En d'autres termes, le lambda ne se définira pas vraiment comme paramètre de la fonction, bien que la portée environnante aura une variable supplémentaire ... Sans la définir cependant, cela ne définirait pas la chaîne comme la chaîne typique [&, & best_string] (string const s). Par conséquent , il est plus probable que nous nous en tenions à cela, essayant de capturer la référence.
la source