Eu estava brincando com lambdas C ++ e sua conversão implícita em ponteiros de função. Meu exemplo inicial foi usá-los como retorno de chamada para a função ftw. Isso funciona conforme o esperado.
#include <ftw.h>
#include <iostream>
using namespace std;
int main()
{
auto callback = [](const char *fpath, const struct stat *sb,
int typeflag) -> int {
cout << fpath << endl;
return 0;
};
int ret = ftw("/etc", callback, 1);
return ret;
}
Depois de modificá-lo para usar capturas:
int main()
{
vector<string> entries;
auto callback = [&](const char *fpath, const struct stat *sb,
int typeflag) -> int {
entries.push_back(fpath);
return 0;
};
int ret = ftw("/etc", callback, 1);
for (auto entry : entries ) {
cout << entry << endl;
}
return ret;
}
Recebi o erro do compilador:
error: cannot convert ‘main()::<lambda(const char*, const stat*, int)>’ to ‘__ftw_func_t {aka int (*)(const char*, const stat*, int)}’ for argument ‘2’ to ‘int ftw(const char*, __ftw_func_t, int)’
Depois de alguma leitura. Aprendi que lambdas usando capturas não podem ser convertidos implicitamente em ponteiros de função.
Existe uma solução alternativa para isso? O fato de não poderem ser convertidos "implicitamente" significa que podem ser convertidos "explicitamente"? (Tentei lançar, sem sucesso). Qual seria uma maneira limpa de modificar o exemplo de trabalho para que eu pudesse anexar as entradas a algum objeto usando lambdas ?.
c++
lambda
function-pointers
c++11
duncan
fonte
fonte
void *
). Se a biblioteca que você está usando permitir esse argumento extra, você encontrará uma solução alternativa. Do contrário, você não tem como conseguir de forma limpa o que deseja fazer.Respostas:
Uma vez que a captura de lambdas precisa preservar um estado, não há realmente uma "solução alternativa" simples, já que elas não são apenas funções comuns. A questão sobre um ponteiro de função é que ele aponta para uma única função global e essa informação não tem espaço para um estado.
A solução alternativa mais próxima (que essencialmente descarta o estado) é fornecer algum tipo de variável global que é acessada de sua função / lambda. Por exemplo, você poderia fazer um objeto functor tradicional e dar a ele uma função de membro estática que se refere a alguma instância única (global / estática).
Mas isso meio que anula todo o propósito de capturar lambdas.
fonte
namespace
e marque-as comothread_local
, essa é aftw
abordagem que escolhi para resolver algo semelhante.Acabei de encontrar esse problema.
O código compila bem sem capturas lambda, mas há um erro de conversão de tipo com captura lambda.
A solução com C ++ 11 é usar
std::function
(editar: outra solução que não requer modificação da assinatura da função é mostrada após este exemplo). Você também pode usarboost::function
(que na verdade é muito mais rápido). Código de exemplo - alterado para que seja compilado, compilado comgcc 4.7.1
:Edit: Eu tive que revisitar isso quando encontrei o código legado onde não pude modificar a assinatura da função original, mas ainda precisava usar lambdas. Uma solução que não requer a modificação da assinatura da função original está abaixo:
fonte
ftw
para tomar emstd::function
vez de um ponteiro de função ...ftw
tivesse um argumento void * userdata, então eu preferiria a resposta de @ evgeny-karpov.ORIGINAL
As funções Lambda são muito convenientes e reduzem um código. No meu caso, precisei de lambdas para programação paralela. Mas requer captura e ponteiros de função. Minha solução está aqui. Mas tome cuidado com o escopo das variáveis que você capturou.
Exemplo
Exemplo com um valor de retorno
ATUALIZAR
Versão melhorada
Já faz um tempo que foi postado o primeiro post sobre lambda C ++ com capturas como um ponteiro de função. Como era utilizável para mim e outras pessoas, fiz algumas melhorias.
A função padrão C pointer api usa a convenção void fn (void * data). Por padrão, essa convenção é usada e lambda deve ser declarado com um argumento void *.
Implementação aprimorada
Exapmle
Convertendo lambda com capturas em um ponteiro C
Pode ser usado dessa forma também
Caso o valor de retorno deva ser usado
E caso os dados sejam usados
fonte
Usando o método localmente global (estático), pode ser feito da seguinte maneira
Suponha que temos
Então, o uso será
Isso funciona porque cada lambda tem uma assinatura exclusiva, portanto torná-la estática não é um problema. A seguir está um wrapper genérico com número variável de argumentos e qualquer tipo de retorno usando o mesmo método.
E uso semelhante
fonte
=
usar&i
em seu loop for.Hehe - uma questão bastante antiga, mas ainda assim ...
fonte
Existe uma maneira hackeada de converter um lambda de captura em um ponteiro de função, mas você precisa ter cuidado ao usá-lo:
/codereview/79612/c-ifying-a-capturing-lambda
Seu código ficaria assim (aviso: compilação do cérebro):
fonte
Minha solução, basta usar um ponteiro de função para se referir a um lambda estático.
fonte
Encontre uma resposta aqui: http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
Ele converte
lambda pointer
paravoid*
e converter de volta quando necessário.para
void*
:auto voidfunction = novo decltype (to_function (lambda)) (to_function (lambda));
de
void*
:função automática = static_cast <std :: function *> (função void);
fonte