2010-07-23 13 views
17

Por favor, mira el siguiente C++ 0x lambda código relacionado:C++ 0x lambda, ¿cómo puedo pasar como parámetro?

typedef uint64_t (*WEIGHT_FUNC)(void* param); 
typedef std::map<std::string, WEIGHT_FUNC> CallbackTable; 

CallbackTable table; 
table["rand_weight"] = [](void* param) -> uint64_t 
{ 
    return (rand() % 100 + 1); 
}; 

me dio un error (en Visual Studio 2010) que el lambda No se pudo convertir al tipo de WEIGHT_FUNC. También sé la respuesta: el uso de std::function object:

typedef std::function<uint64_t (void*)> WEIGHT_FUNC; 

Sin embargo, también quiero saber cómo puedo recibir el tipo de lambda sin el uso de std::function. ¿Qué tipo debería ser?

+1

'auto'? _______ – kennytm

+2

auto solo será útil para determinar automáticamente el tipo, no es un tipo de variante, no puede ser un parámetro. – Klaim

+2

¿Qué compilador estás usando? Parece que tu compilador no es estándar en cuanto a lambda, deberían poder convertir implícitamente a un puntero de función (en casos como este). – GManNickG

Respuesta

20

La conversión a funcionar puntero es relativamente nuevo: Se introdujo con N3043 el 15 de febrero de 2010.

Mientras que, por ejemplo, GCC 4.5 lo implementa, Visual Studio 10 se lanzó el 12 de abril de 2010 y, por lo tanto, no lo implementó a tiempo. Como James señaló, este will be fixed en versiones futuras.

Por el momento, debe utilizar una de las soluciones alternativas que se proporcionan aquí.

Técnicamente algo parecido a la siguiente solución funcionaría, pero sin variadic plantillas de su no es divertido para generalizarlo (Boost.PP al rescate ...) y no hay red de seguridad contra lambdas paso de captura en:

typedef uint64_t (*WeightFunc)(void* param); 

template<class Func> WeightFunc make_function_pointer(Func& f) { 
    return lambda_wrapper<Func>::get_function_pointer(f); 
} 

template<class F> class lambda_wrapper { 
    static F* func_; 
    static uint64_t func(void* p) { return (*func_)(p); }  
    friend WeightFunc make_function_pointer<>(F& f);  
    static WeightFunc get_function_pointer(F& f) { 
     if (!func_) func_ = new F(f); 
     return func; 
    } 
}; 

template<class F> F* lambda_wrapper<F>::func_ = 0; 

// ... 
WeightFunc fp = make_function_pointer([](void* param) -> uint64_t { return 0; }); 
+8

Vale la pena mencionar que la conversión a punteros de función es solo para funciones lambda sin estado, no pueden capturar el alcance léxico. –

+0

Parece que la conversión al puntero a la función no funciona con g ++ 4.5 en el código de la plantilla (http://tinyurl.com/3y6hkyq) – rafak

+0

Consulte http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45080 para ese . –

-1

intento con (no probado):

#include <function> 

typedef std::function< int64_t (void*) > weight_func; 
typedef std::map<std::string, weight_func > CallbackTable; 

No creo que hay alguna otra manera de hacerlo que utilizar std :: función o equivalente.

+0

Gracias por la corrección sbi – Klaim

+3

No use 'std :: function ', use 'std :: function '. –

+0

¡Correcto! Reparado, gracias! – Klaim

1

Si realmente insisten en no usar function<> entonces probablemente podría utilizar decltype:

typedef decltype([](void*)->uint_64{return 0;}) my_lambda_type; 

Realmente no recomiendo esto, sin embargo, ya que está drásticamente limitar a ti mismo y ni siquiera sabe si dos Las lambda con la misma firma tienen la garantía de ser del mismo tipo.

+0

Se garantiza que el tipo generado será el mismo que si escribe exactamente el mismo tipodef en alguna parte ¿más? No creo que deba suponer que el tipo depende de la firma ... pero tal vez estoy equivocado. – Klaim

+0

No funciona en GCC. –

+1

Respuesta anterior, lo sé, pero la expresión lambda no puede aparecer en un contexto no evaluado. (Creo que el razonamiento es lo que mencionó: dado que cada expresión lambda es un tipo único, no especificado, no se garantiza ninguna respuesta significativa particular y un contexto no evaluado). – GManNickG

Cuestiones relacionadas