Используя std:: bind с функцией-членом, используйте указатель объекта или нет для этого аргумента?
При использовании std::bind
для привязки функции-члена первым аргументом является указатель объектов this
. Однако он работает, передавая объект как указатель, а не.
См., например, следующую программу:
#include <iostream>
#include <functional>
struct foo
{
void bar(int v) { std::cout << "foo::bar - " << v << '\n'; }
};
int main()
{
foo my_foo;
auto f1 = std::bind(&foo::bar, my_foo, 1);
auto f2 = std::bind(&foo::bar, &my_foo, 2);
f1();
f2();
}
Оба clang и GCC компилируют это без жалоб, и результат работает для обоих binds:
foo::bar - 1
foo::bar - 2
Я пытаюсь обвести голову вокруг спецификации (раздел 20.8.9), но это одно из мест, где это далеко не ясно для меня.
Должен ли только один быть правильным или оба правильны?
Ответы
Ответ 1
Оба правильные. 20.8.9.1.2 перейдите к 20.8.2, чтобы описать требования и влияние вашего вызова на bind
. 20.8.2:
20.8.2 Требования [func.require]
1 Определите INVOKE (f, t1, t2, ..., tN)
следующим образом:
- (t1.*f)(t2, ..., tN)
, когда f
является указателем на функцию-член класса T
и t1
является объектом типа T
или ссылкой на объект типа T
или ссылкой к объекту типа, полученного из T
;
- ((*t1).*f)(t2, ..., tN)
, когда f
является указателем на функцию-член класса T
и t1
не является одним из типов, описанных в предыдущем элементе;
- t1.*f
, когда N == 1
и f
является указателем на данные элемента класса T
и t1
является объектом типа T
или ссылкой на объект типа T
или ссылку на объект типа, полученного из T
;
- (*t1).*f
, когда N == 1
и f
является указателем на данные элемента класса T
и t1
не является одним из типов, описанных в предыдущем элементе;
- f(t1, t2, ..., tN)
во всех остальных случаях.
Первые две опции позволяют использовать как ссылку, так и указатель.
Важно отметить, что формулировка не ограничивает вас указателями. Вы могли бы использовать std::shared_ptr
или какой-либо другой умный указатель, чтобы сохранить ваш экземпляр живым, пока он связан, и он все равно будет работать с std::bind
, поскольку t1
разыменовывается независимо от того, что это (дано, конечно, возможно).
Ответ 2
Чтобы добавить к правильному ответу (что обе формы разрешены).
Я думаю о двух вариантах привязки по аналогии с объявлением аргумента функции, которые могут быть "переданы по значению" или "переданы по ссылке".
В случае f1
(также передавая my_foo
"по значению" ) результат не "видит" любые изменения, сделанные в my_foo
за точкой привязки. Это может быть нежелательно, особенно если my_foo
развивается. "По значению" привязка имеет дополнительную "стоимость" (нескольких) вызовов конструктора копирования.
Ответ 3
Есть разница. Поскольку rytis выдвигается, передача по значению не видит изменений, внесенных в my_foo. Например, в случае, если my_foo является классом, передача по значению не видит изменений, внесенных в данные элемента my_foo.