Подтвердить что ты не робот

Использует boost:: bind для передачи большего количества аргументов, чем ожидалось?

Использование , в результате получится может принимать больше аргументов, чем ожидал связанный объект, Концептуально:

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 с другим количеством аргументов, чем ожидает целевой объект . Это лучшая гарантия?

4b9b3361

Ответ 1

Да, это безопасно и портативно – как указано в документации, выражение bind, возвращаемое boost::bind, молча игнорирует дополнительные аргументы.

I.e., в вашем первом примере func получает не значения 1, 2 и 3boundFunc получает значения 1, 2 и 3 и перенаправляет их в содержащееся bind-expression, которое безопасно принимает и игнорирует их, а затем вызывает func(). Аналогично, в вашем втором примере zeroArg получает значение 42 и перенаправляет его в содержащееся bind-expression, которое принимает и игнорирует значение, а затем вызывает func0().