2012-04-07 6 views
5

Creo que el siguiente para ser una forma más barata de la unión variable local al cierre:La manera más barata de la unión variable local al cierre

void ByRValueReference(A&& a) { 
} 

std::function<void()> CreateClosureByRValueReference() { 
    A a; 
    std::function<void()> f = std::bind(&ByRValueReference, std::move(a)); // !!! 
    return f; 
} 

Sin embargo, no se compila bajo Clang 3.1:

error: no viable conversion from '__bind<void (*)(A &&), A>' to 'std::function<void()>' 

y gcc 4.6.1:

/usr/include/c++/4.6/functional:1778:2: error: no match for call to ‘(std::_Bind<void (*(A))(A&&)>)()’ 

¿Estoy violando la norma o simplemente se han roto las bibliotecas estándar?

+1

Creo que es 'function '. – RedX

+2

Lo que en realidad es un poco costoso aquí es 'std :: function'. Si realmente te importa la eficiencia, yo devolvería 'decltype (std :: bind (...))' – pmr

Respuesta

3

Esto es por diseño de std::bind. La especificación completa está en 20.8.9.1.2 función de plantilla bind [func.bind.bind] pero en este caso el último punto del párrafo 10 (que describe cómo se utilizan los parámetros ligados) se aplica:

- de lo contrario , el valor es tid y su tipo Vi es TiD cv &

Así, en otras palabras, std::move(a) resultará en la envoltura llamada almacenar un A (de construcción movimiento), y luego, cuando se utiliza operator() a este miembro será remitida como lvalue (con cv-qualifiers que coinciden con los cv-qualifiers del wrapper de llamadas, pero estoy divagando). A pesar de que fue aprobado como un valor.

Este tipo de desajuste puede ser resuelto a través de una lambda:

std::bind([](A& a) { ByRValueReference(std::move(a)); }, std::move(a)) 

Esto puede argumentar que es más explícito que otras llamadas a la llamada resultante envuelta son dudosas (puesto que el miembro A es susceptible de haber sido movido desde), pero no soy demasiado aficionado al comportamiento de std::bind como un todo.

+0

Si vas con una lambda, podrías devolver '[& a]() {...}' directamente y ahorrarse el enlace ... –

+0

@KerrekSB Esto tiene una semántica diferente a la llamada a 'std :: bind' y en el caso del OP conducirá a UB. –

+0

Oh, ya veo, de hecho. Gracias. –

Cuestiones relacionadas