Использование boost-bind, в результате получится boost-function может принимать больше аргументов, чем ожидал связанный объект, Концептуально:
int func() { return 42; }
boost::function<int (int,int,int)> boundFunc = boost::bind(&func);
int answer = boundFunc(1,2,3);
В этом случае func()
получает 1,2 и 3 в стеке, даже если его подпись указывает, что он не принимает аргументов.
Это отличается от более типичного использования boost::bind
для частичного приложения, где значения фиксированы для определенных объектов, дающих boost::function
, что принимает меньше аргументов, но предоставляет правильное количество аргументов при вызове связанного объекта.
Следующий код работает как с MSVС++ 2010 SP1. Это сокращенная форма для публикации; исходный код также работает под g++ 4.4 в Linux.
Являются ли следующие четко определенные в соответствии со стандартом С++?
#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()
Я понимаю, почему работает zeroArg(42)
: неиспользуемый аргумент помещается в стек с помощью вызывающей подпрограммы и просто не открывается вызываемой процедурой. Когда вызванная процедура возвращается, вызывающая процедура очищает стек. Поскольку он помещает аргументы в стек, он знает, как их удалить.
Переместится в другую архитектуру или С++ компилятор перерыв? Будет ли более агрессивная оптимизация нарушить это?
Я ищу более сильное выражение либо из документации Boost, либо из документа Standards. Я тоже не смог найти однозначную позицию.
Используя отладчик и глядя на сборку и стек, ясно, что func
из первого примера не получает значения 1,2 и 3: вы правы на этом фронте. То же самое верно для func0
во втором примере. Это верно, по крайней мере, для реализаций, на которые я смотрю, MSVС++ 2010SP1 и g++ 4.4/Linux.
Глядя на документацию Boost с ссылкой, это не так ясно, как хотелось бы, что безопасно передавать дополнительные аргументы:
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)
Обратите внимание, что в последнем примере объект функции, созданный
bind(g, _1, _1, _1)
, не содержит ссылок на какие-либо аргументы за пределами первого, но он все равно может использоваться с несколькими аргументами. Любые дополнительные аргументы молча игнорируются, так же как первый и второй аргументы игнорируются в третьем примере. [Emphasis mine.]
Утверждение о игнорировании дополнительных аргументов не так однозначно, как я хотел бы убедить меня, что это верно в общем случае. Глядя на TR1, из раздела 3.6.3 ясно, что можно возвращать вызываемый объект из bind
с другим количеством аргументов, чем ожидает целевой объект . Это лучшая гарантия?