É possível capturar por referência const em uma expressão lambda?
Quero que a tarefa marcada abaixo falhe, por exemplo:
#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;
}
Atualização: Como essa é uma pergunta antiga, pode ser bom atualizá-la se houver recursos no C ++ 14 para ajudar nisso. As extensões no C ++ 14 nos permitem capturar um objeto não const por referência const? ( Agosto de 2015 )
[&, &best_string](string const s) { ...}
:?Respostas:
const
não está na gramática para capturas a partir de n3092:O texto menciona apenas captura por cópia e captura por referência e não menciona nenhum tipo de constância.
Parece uma supervisão para mim, mas não acompanhei o processo de padronização de muito perto.
fonte
const
. Ou, mais corretamente, se a variável de captura fosseconst
, o compilador aplicaria o comportamento correto no programador. Seria bom se a sintaxe fosse suportada[&mutableVar, const &constVar]
.a
comoconst
, declararconst auto &b = a;
antes do lambda e capturab
[&foo = this->foo]
dentro de umaconst
função, aparece um erro informando que a própria captura descarta qualificadores. Isso poderia ser um bug no GCC 5.1, suponho.No c ++ 14usando
static_cast
/const_cast
:DEMO
No c ++ 17usando
std::as_const
:DEMO 2
fonte
const_cast
pode incondicionalmente mudar um objeto volátil para um objeto const (quando solicitado a elenco paraconst
), assim, para a adição de restrições prefirostatic_cast
static_cast
a referência const pode silenciosamente criar um temporária se você não obter o tipo exatamente certo&basic_string = std::as_const(best_string)
deve resolver todos os problemasconst& best_string
.Eu acho que a parte de captura não deve especificar
const
, como a captura significa, ela só precisa de uma maneira de acessar a variável de escopo externo.O especificador é melhor especificado no escopo externo.
A função lambda é const (não pode alterar o valor em seu escopo); portanto, quando você captura uma variável por valor, a variável não pode ser alterada, mas a referência não está no escopo lambda.
fonte
better_string
dentro do escopo que contém, esta solução não funcionará. O caso de uso para capturar como const-ref é quando a variável precisa ser mutável no escopo que o contém, mas não dentro do lambda.const string &c_better_string = better_string;
e passar feliz para a lambda:[&c_better_string]
Acho que se você não estiver usando a variável como parâmetro do functor, deverá usar o nível de acesso da função atual. Se você acha que não deveria, então separe seu lambda dessa função, ela não faz parte dela.
De qualquer forma, você pode facilmente obter o mesmo que deseja usando outra referência const:
Mas é o mesmo que assumir que seu lambda precisa ser isolado da função atual, tornando-o não lambda.
fonte
best_string
apenas. Além disso, o GCC 4.5 "rejeita com êxito" o código como pretendido.Eu acho que você tem três opções diferentes:
usando uma cópia
A parte interessante sobre lambdas com capturas de cópias é que elas são apenas de leitura e, portanto, fazem exatamente o que você deseja.
usando std :: bind
std::bind
reduz a aridade de uma função. Observe, no entanto, que isso pode / levará a uma chamada de função indireta através de um ponteiro de função.fonte
Existe um caminho mais curto.
Observe que não há e comercial antes de "best_string".
Será do tipo "const std :: reference_wrapper << T >>".
http://coliru.stacked-crooked.com/a/0e54d6f9441e6867
fonte
Use clang ou aguarde até que esse bug do gcc seja corrigido: bug 70385: A captura do Lambda por referência da referência const falha [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]
fonte
O uso de uma const simplesmente faz com que o e comercial do algoritmo defina a string como seu valor original. Em outras palavras, o lambda não se definirá realmente como parâmetro da função, embora o escopo ao redor tenha uma variável extra ... Sem defini-la no entanto, ela não definiria a string como o típico [&, & best_string] (string const s) Portanto , é mais provável que seja melhor deixarmos assim, tentando capturar a referência.
fonte