Могу ли я привязываться к функции, которая принимает аргументы по умолчанию, а затем вызывает ее?
Как я могу привязать к функции, которая принимает аргументы по умолчанию, без указания аргументов по умолчанию, а затем вызывать ее без каких-либо аргументов?
void foo(int a, int b = 23) {
std::cout << a << " " << b << std::endl;
}
int main() {
auto f = std::bind(foo, 23, 34); // works
f();
auto g = std::bind(foo, 23); // doesn't work
g();
using std::placeholders::_1;
auto h = std::bind(foo, 23, _1); // doesn't work either
h();
}
Ответы
Ответ 1
В принципе, каждый раз, когда вы пишете foo(x)
, компилятор переводит его на foo(x, 23);
. Он работает только в том случае, если у вас есть прямой вызов с именем функции. Вы не можете, например, назначить &foo
на void(*)(int)
, потому что подпись функции void(int, int)
. Параметры по умолчанию не играют роли в подписи. И если вы присваиваете его переменной void(*)(int, int)
, информация о параметре по умолчанию теряется: вы не можете использовать параметр по умолчанию через эту переменную. std::bind
хранит void(*)(int, int)
где-то в его недрах и, таким образом, теряет информацию о параметрах по умолчанию.
В С++ нет способа получить значение по умолчанию параметра из-за пределов функции, поэтому вы привязываетесь вручную, предоставляя значение по умолчанию при связывании.
Ответ 2
Я думаю, вы могли бы имитировать поведение, которое вы хотите, используя лямбда.
Что-то вроде этого:
auto g = [] (){ foo( 23 ); };
EDIT: просто проверено и, кажется, работает нормально: http://ideone.com/SPSvi
Ответ 3
У меня есть два решения:
1 - Вы можете перегрузить foo() и вызвать вызов оригинала по умолчанию:
void foo(int a, int b)
{
std::cout << a << " " << b << std::endl;
}
inline void foo(int a)
{
foo(a, 23);
}
2 - Вы можете использовать статическую переменную по умолчанию, а затем использовать ее в процессе привязки:
static int foo_default_b = 23;
void foo(int a, int b = foo_default_b)
{
std::cout << a << " " << b << std::endl;
}
auto g = std::bind(foo, 23, foo_default_b);
g();
Ответ 4
Этот ответ не согласен с ответом Р. Мартиньо Фернандеса. Вы действительно можете использовать boost::bind
для привязки к параметрам по умолчанию, вам просто нужно поместить заполнители, так:
boost::bind<void (int, int)>(foo, _1, _2)(12);
Это вызовет foo(12, 23)
, как и ожидалось. Хотя я не тестировал этот конкретный код, я сделал что-то подобное в своем коде на основе ответа, связанного выше, и работает в gcc 4.8.5
.
Хм, я только заметил, что это спрашивает о std::bind
, а не boost::bind
. Я не знаю, какие отличия есть, если они есть.