Используя std :: bind с функцией-членом, используйте указатель объекта или нет для этого аргумента?

При использовании std::bind для привязки функции-члена первым аргументом являются объекты this указателя. Однако он работает, передавая объект как указатель, а не.

См., Например, следующую программу:

 #include  #include  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 компилируют это без жалоб, и результат работает для обеих привязок:

 foo :: bar - 1
 foo :: bar - 2

Я пытался обвести голову вокруг спецификации (раздел 20.8.9), но это одно из мест, где мне это пока что не ясно.

Должен ли только один быть правильным или оба правильны?

Оба правильные. 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 является указателем на функцию-член classа T а t1 является объектом типа T или ссылкой на объект типа T или ссылкой на объект типа, полученного из T ;

((*t1).*f)(t2, ..., tN) когда f является указателем на функцию-член classа T и t1 не является одним из типов, описанных в предыдущем пункте;

t1.*f когда N == 1 и f – указатель на данные члена classа T а t1 – объект типа T или ссылка на объект типа T или ссылку на объект типа, полученного из T ;

(*t1).*f когда N == 1 и f является указателем на данные члена classа T и t1 не является одним из типов, описанных в предыдущем пункте;

f(t1, t2, ..., tN) во всех остальных случаях.

Первые два варианта позволяют как ссылку, так и указатель.

Важно отметить, что формулировка не ограничивает вас указателями. Вы можете использовать std::shared_ptr или какой-либо другой умный указатель, чтобы сохранить ваш экземпляр живым при привязке, и он все равно будет работать с std::bind поскольку t1 разыменовывается независимо от того, что это (дается, конечно, что это возможно) ,

Чтобы добавить к правильному ответу (разрешить обе формы).

Я думаю о двух вариантах привязки по аналогии с объявлением аргумента функции, которые могут быть «переданы по значению» или «переданы по ссылке».

В случае f1 (aka my_foo «по значению») результат не «видит» любые изменения, внесенные в my_foo после точки привязки. Это может быть нежелательно, особенно если my_foo развивается. «По значению» привязка имеет дополнительную «стоимость» (нескольких) вызовов конструктора копирования.

Есть разница. Поскольку rytis выдвигается, передача по значению не видит изменений, внесенных в my_foo. Например, в случае, если my_foo является classом, передача по значению не видит изменений, внесенных в данные элемента my_foo.

  • Удаленный конструктор по умолчанию. Объекты все еще могут быть созданы ... иногда
  • Является ли stl-вектор одновременным чтением streamобезопасным?
  • Доступ к атрибутам на литералах работает на всех типах, но не `int`; Зачем?
  • int a = {1,2,}; Разрешена странная запятая. Любая конкретная причина?
  • Вычисления без последствий (ака последовательности)
  • Является ли сдвиг слева (<<) отрицательным целым неопределенным поведением в C ++ 11?
  • Указывает ли объявление, использующее «авто», выражение extern, использующее спецификатор конкретного типа?
  • Эффективный беззнаковый кран, исключающий поведение, определяемое реализацией
  • Является ли std :: abs (0u) плохо сформированным?
  • Давайте будем гением компьютера.