2011-10-10 7 views
37
#include <vector> 
#include <algorithm> 

void foo(int) 
{ 
} 

int main() 
{ 
    std::vector<int> v({ 1,2,3 }); 

    std::for_each(v.begin(), v.end(), [](auto it) { foo(it+5); }); 
} 

cuando se compila, el ejemplo anterior se inicia la salida de error como este:El uso de automóviles en una función lambda

h4.cpp: In function 'int main()': 
h4.cpp:13:47: error: parameter declared 'auto' 
h4.cpp: In lambda function: 
h4.cpp:13:59: error: 'it' was not declared in this scope 

¿Quiere decir que la palabra clave auto no debe utilizarse en las expresiones lambda?

Esto funciona:

std::for_each(v.begin(), v.end(), [](int it) { foo(it+5); }); 

Por qué la versión con la palabra clave automático no funciona?

+1

Creo que incluso si se trata de una lambda, que todavía funcionan como una función, y debe tener una firma. Con el auto, deja que el compilador decida el tipo, por lo que su lambda no tiene una firma real hasta el tiempo de compilación. – Geoffroy

+3

Realmente necesitamos lambdas polimórficos (plantillas implícitas AKA) en el próximo estándar. Esta pregunta es solo una de varias instancias donde la gente simplemente asume que 'auto' funciona de esta manera. No veo ninguna razón por la que no debería. –

+0

deft_code, estoy contigo.Es un caso de uso lógico para auto. – Robert

Respuesta

63

palabra clave auto no funciona como un tipo para argumentos de función. Si no desea utilizar el tipo real en las funciones lambda, puede usar el siguiente código.

for_each(begin(v), end(v), [](decltype(*begin(v)) it){ 
     foo(it + 5);   
}); 
+37

Vamos a obtener el soporte 'auto' en lambdas en [C++ 14] (http://en.wikipedia.org/wiki/C%2B%2B14#Generic_lambdas). –

+0

Ten en cuenta la estrella antes del 'begin (v)' en 'decltype'. Desea que el tipo de valor no sea el tipo de iterador. (mensajes de error cuando fallas que serán misteriosos). –

4

El tipo de la lambda necesita ser conocida antes de que el compilador puede incluso crear una instancia std::for_each. Por otro lado, incluso si fuera teóricamente posible, ese auto solo podía deducirse después de que se haya instanciado for_each al ver cómo se invoca el funtor.

Si es posible, se olvidan de for_each y usar el rango basado en los bucles que son mucho más simple:

for (int it : v) { 
    foo(it + 5); 
} 

Esto también debe hacer frente muy bien con auto (y auto& y const auto&).

for (auto it : v) { 
    foo(it + 5); 
} 
+0

Sí, pero eso solo funciona con for_each, y no con otros algoritmos. p.ej. quieres ordenar una lambda – CashCow

20

Esto fue discutido brevemente por Herb Sutter durante una entrevista. Su demanda de auto argumentos es, de hecho, no es diferente de demanda que cualquier función debe ser declarable con auto, así:

auto add(auto a, auto b) -> decltype(a + b) { return a + b; } 

Sin embargo, tenga en cuenta que esto no es realmente una función en absoluto, sino que es una función plantilla, similar a:

template <typename S, typename T> 
auto add(S a, T b) -> decltype(a + b) { return a + b; } 

por lo que son esencialmente pidiendo una instalación para activar cualquier función en una plantilla cambiando sus argumentos. Dado que las plantillas son un tipo de entidad muy diferente en el sistema de tipos de C++ (piense en todas las reglas especiales para plantillas, como búsqueda y deducción en dos fases), esto sería un cambio de diseño radical con ramificaciones imprevisibles, que ciertamente no es Va a estar en el estándar pronto.

+1

No, no pregunta o exige :) Me preguntaba por qué no funciona. –

+5

Bueno, es esencialmente la misma razón que para "por qué no son todas las plantillas de funciones", simplemente no encaja en el diseño del lenguaje. –

Cuestiones relacionadas