Используя boost-bind , результирующая boost-функция может получить больше аргументов, чем ожидает связанный объект.Концептуально:
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
, который принимает меньше аргументов, но предоставляет правильное количество аргументов при вызове связанного объекта.
Следующий код работает с MSVC ++ 2010 SP1.Это сокращенная форма для публикации;исходный код также работает в g ++ 4.4 в Linux.
Является ли следующее хорошо определенным в соответствии со стандартом 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()
Я понимаю, почему zeroArg(42)
работает: неиспользуемый аргумент помещается в стек вызывающей подпрограммой и просто не вызывается вызываемой подпрограммой.Когда вызываемая подпрограмма возвращается, вызывающая подпрограмма очищает стек.Поскольку он помещает аргументы в стек, он знает, как их удалить.
Не нарушит ли это переход на другую архитектуру или c ++ компилятор?Разве более агрессивная оптимизация сломает это?
Я ищу более сильное утверждение либо из документации Boost, либо из документа стандартов.Мне также не удалось найти однозначную позицию.
Используя отладчик и просматривая сборку и стек, становится ясно, что func
из первого примера не получает значения 1,2 и 3: вы правы в этом отношении.То же самое верно для func0
во втором примере.Это верно, по крайней мере, для тех реализаций, на которые я смотрю, MSVC ++ 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)
, не содержит ссылок на какие-либо аргументы, кроме первого, но он все еще может бытьиспользуется с более чем одним аргументом. Любые дополнительные аргументы игнорируются, как первый и второй аргументы игнорируются в третьем примере. [Выделение мое.]
ОператорПро игнорирование дополнительных аргументов не так однозначно, как я хотел бы убедить меня, что это верно в общем случае.Глядя на TR1 , из раздела 3.6.3 становится ясно, что вызываемый объект , возвращаемый из bind
, может быть вызван с другим числом аргументов, чем целевой объект ожидает.Это лучшая гарантия?