Pregunta

Hace un tiempo usé std::function más o menos así:

std::function<void(int)> func = [](int i) -> int { return i; };

Básicamente, hice esto porque quería almacenar diferentes objetos de función en un std::function, pero no quería restringir los tipos de devolución de estas funciones.Como esto parecía funcionar, lo seguí.Pero no estoy convencido de que sea seguro de usar y no he podido encontrar ninguna documentación al respecto.¿Alguien sabe si este uso es legítimo?O más generalmente, ¿cuáles son las reglas para el objeto que puede asignarse con seguridad a un std::function?

Editar

Para aclarar, el problema que me preocupa es que la función lambda devuelve un int, mientras func se declara con tipo de retorno void.No estoy seguro de si esto está bien, especialmente después de una llamada a func() está hecho.

¿Fue útil?

Solución

Su código tiene un comportamiento indefinido. Puede o no funcionar como espere. La razón por la que tiene un comportamiento indefinido es por 20.8.11.2.1 [func.wrap.func.con]/p7:

Requiere: F será CopyConstructible. f será llamable (20.8.11.2) para los tipos de argumentos ArgTypes y tipo de retorno R.

Para f para ser llamable para el tipo de devolución R, f debe devolver algo implícitamente convertible al tipo de retorno del std::function (void en tu caso). Y int no es implícitamente convertible para void.

Esperaría que su código funcione en la mayoría de las implementaciones. Sin embargo, en al menos una implementación (libc ++), no puede compilar:

test.cpp:7:30: error: no viable conversion from 'int (int)' to 'std::function<void (int)>'
    std::function<void(int)> ff = f;
                             ^    ~

Irónicamente, la justificación de este comportamiento proviene de otra pregunta.

La otra pregunta presentó un problema con std::function uso. La solución a ese problema implicó que la implementación aplique el Requiere: cláusula en el momento de la compilación. En contraste, la solución al problema de esta pregunta es amenazante la implementación de hacer cumplir el Requiere: cláusula.

Otros consejos

Su caso de uso está bien definido según el estándar.

Estás construyendo un std::function de un objeto invocable[1]

§20.8.11.2.1/7:

template<class F> function(F f);

Requiere:F será CopyConstructible.f será llamable (20.8.11.2) para los tipos de argumentos Argtypes y el tipo de retorno R.

Entonces, ¿tu f callable?

§20.8.11.2/2 dice:

Un objeto llamable F de tipo F es llamable para los tipos de argumentos Argtypes y return Type R si la expresión INVOKE (f, declval<ArgTypes>()..., R), considerado como un operando no evaluado (cláusula 5), ​​está bien formado (20.8.2).

Y la definición de INVOKE dice:

§20.8.2

  1. Definir INVOKE (f, t1, t2, ..., tN) como sigue:...cosas relacionadas con punteros de función miembro/var...— f(t1, t2, ..., tN) en todos los otros casos.

  2. Definir INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) convertido implícitamente a R.

Y dado que cualquier tipo se puede convertir implícitamente a void, su código debería funcionar bien con un compilador que cumpla con los estándares. Como lo señala litb a continuación, no hay una conversión implícita a nula, por lo que esto no está bien definido.

[1]:Creo que lambda cuenta aquí como un objeto invocable, aunque no tengo una referencia para eso.Su lambda también podría usarse como puntero de función, ya que no captura ningún contexto.

Parece que puede estar bien para las funciones anónimas.

Cita de http://www.alorelang.org/release/0.5/doc/std_function.html (Esto no es de la biblioteca estándar C ++, sin embargo, parece que están usando algo similar en enlaces a C ++)

Los objetos de función solo se pueden crear con una definición de función, una expresión de funciones anónimas o accediendo a un método límite usando el operador Dot (.).

Otra forma en que esto podría hacerse almacenando el puntero de la función en Auto como se ve aquí: http://en.wikipedia.org/wiki/anonymous_function (Sección C ++)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top