2011-09-12 10 views
24

Con , el resultante puede recibir más argumentos de los esperados. Conceptualmente:¿Está usando boost :: bind para pasar más argumentos de los esperados?

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 tiene argumentos.

Esto difiere de la utilización más típica de boost::bind para partial application, donde los valores se fijan para ciertos objetos produciendo un boost::function que toma menos argumentos pero suministra el número correcto de argumentos cuando se invoca el objeto unido.

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

¿Está lo siguiente bien definido según 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é zeroArg(42) obras: el argumento no utilizado se pone en la pila por la rutina de llamada y simplemente no accede a la rutina de llamada. Cuando la rutina llamada vuelve, la rutina de llamada limpia la pila. Como puso los argumentos en la pila, sabe cómo eliminarlos.

¿Va a cambiar a otra arquitectura o compilatorio romper esto? ¿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 conjunto y la pila, está claro que func del primer ejemplo no recibe los valores 1,2, y 3: 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.

En cuanto a la documentación mencionada Boost, que no es tan clara como me gustaría que es seguro para 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 producida 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. [El subrayado es mío.]

La declaración acerca de los argumentos adicionales que son ignorados no es tan inequívoca como me gustaría para convencerme de que esto es cierto en el caso general. Mirando TR1, es claro desde Sec 3.6.3 que un objeto invocable devuelto desde bind se puede invocar con un número de argumentos diferente al esperado objeto.¿Es esa la mejor garantía disponible?

+5

+1 para una primera pregunta perfecta. Te quiero un poco –

Respuesta

14

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

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

+3

De hecho. 'func()' no recibe mágicamente más objetos en la pila de llamadas de lo que espera; 'boost :: bind' (una función intermediaria, realmente) los acepta (y está bien con eso) y luego simplemente no los pasa al eventual llamado. –

+0

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

Cuestiones relacionadas