c++ boost boost-bind boost-function

c++ - ¿Está usando boost:: bind para pasar más argumentos de los esperados?



boost-bind boost-function (1)

Usando boost-bind , la boost-function resultante puede recibir más argumentos de los esperados. Conceptualmente:

int func() { return 42; } boost::function<int (int,int,int)> boundFunc = boost::bind(&func); int answer = boundFunc(1,2,3);

En este caso, func() recibe 1,2 y 3 en la pila, aunque su firma indica que no necesita argumentos.

Esto difiere del uso más típico de boost::bind para la aplicación parcial , donde los valores se fijan para ciertos objetos que producen una boost::function que toma menos argumentos pero proporciona la cantidad correcta de argumentos cuando se invoca el objeto enlazado.

El siguiente código funciona con MSVC ++ 2010 SP1. Esta es una forma reducida de publicar; el código original también funciona bajo g ++ 4.4 en Linux.

¿Está el siguiente bien definido de acuerdo con el estándar C ++?

#include <iostream> #include <boost/bind.hpp> #include <boost/function.hpp> using namespace std; void func1(int x) { std::cout << "func1(" << x << ")/n"; } // end func1() void func0() { std::cout << "func0()/n"; } // end func0() int main(int argc,char* argv[]) { typedef boost::function<void (int)> OneArgFunc; OneArgFunc oneArg = boost::bind(&func1,_1); // here we bind a function that accepts no arguments OneArgFunc zeroArg = boost::bind(&func0); oneArg(42); // here we invoke a function that takes no arguments // with an argument. zeroArg(42); return 0; } // end main()

Entiendo por qué funciona zeroArg(42) : el argumento no utilizado es puesto en la pila por la rutina de llamada y simplemente no se accede por la rutina llamada. Cuando la rutina llamada vuelve, la rutina de llamada limpia la pila. Como puso los argumentos en la pila, sabe cómo eliminarlos.

¿Cambiar esto a otra arquitectura o compilador de C ++ ? ¿Romperá esto una optimización más agresiva?

Estoy buscando una declaración más sólida, ya sea de la documentación de Boost o del documento de Estándares. No he podido encontrar una posición inequívoca en ninguno de los dos.

Usando un depurador y mirando el ensamblado y la pila, está claro que el func del primer ejemplo no recibe los valores 1, 2 y 3: usted está correcto en ese frente. Lo mismo es cierto para func0 en el segundo ejemplo. Esto es cierto al menos para las implementaciones que estoy viendo, MSVC ++ 2010SP1 y g ++ 4.4 / Linux.

Al mirar la documentación de Boost a la que se hace referencia, no está tan claro como me gustaría que sea seguro pasar argumentos adicionales:

bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x)

Tenga en cuenta que, en el último ejemplo, el objeto de función producido por bind(g, _1, _1, _1) no contiene referencias a ningún argumento más allá del primero, pero aún se puede usar con más de un argumento. Cualquier argumento adicional se ignora silenciosamente, al igual que el primer y el segundo argumento se ignoran en el tercer ejemplo. [Énfasis mío.]

La afirmación de que se ignoran los argumentos adicionales no es tan inequívoca como me gustaría convencerme de que esto es cierto en el caso general. Mirando TR1 , está claro desde la Sec. 3.6.3 que un objeto recuperable devuelto por un bind puede invocarse con un número de argumentos diferente al que el objeto objetivo espera. ¿Es esa la mejor garantía disponible?


Sí, esto es seguro y portátil: como se menciona explícitamente en la documentación , la expresión de enlace devuelta por boost::bind ignora silenciosamente los argumentos adicionales.

Es decir, en su primer ejemplo, func no recibe los valores 1 , 2 y 3 - boundFunc recibe los valores 1 , 2 y 3 y los reenvía a la expresión bind contenida, que los recibe e ignora de manera segura, y luego invoca func() . Del mismo modo, en su segundo ejemplo, zeroArg recibe el valor 42 y lo reenvía a la expresión bind contenida, que recibe e ignora el valor y luego llama a func0() .