std :: bind с переменной функцией-членом шаблона и универсальными ссылками - PullRequest
1 голос
/ 18 октября 2019

Здесь у меня есть небольшой кусочек кода, и он прекрасно компилируется и работает (по крайней мере, с моим GCC 7.3.0 и Ubuntu 18.04):

#include <functional>
#include <string>
#include <iostream>

void func(int a, const std::string& b, const std::string& c)
{
  std::cout << a << b << c << std::endl;
}

class Test
{
public:
  template <typename ... ARGS>
  bool func_to_bind(ARGS&& ... args) const {
    func(args...);
    return true;
  }

  template <typename ... ARGS>
  void binding_func(ARGS&& ... args) const 
  {
    auto func_obj = std::bind(&Test::func_to_bind<int&, ARGS&...>, this, 42, args...);
    func_obj();
  }
};


int main()
{
  Test obj;
  obj.binding_func(std::string("one"), std::string("two"));
}

Часть, которую я не понимаю, этострока:

std::bind(&Test::func_to_bind<int&, ARGS&...>, this, 42, args...);

Почему компилятор требует использовать ссылки в качестве параметров типа шаблона? Если я удалю ссылку из int следующим образом:

std::bind(&Test::func_to_bind<int, ARGS&...>, this, 42, args...);

Он не скомпилируется. Также, если я изменю подпись func_to_bind на это:

bool func_to_bind(ARGS& ... args) const

Он будет прекрасно компилироваться даже при отсутствии ссылки. Кто-нибудь может объяснить, что именно здесь происходит? Я также провел некоторый поиск и нашел этот вопрос: Как объединить std :: bind (), шаблоны variadic и идеальную пересылку?

Но я не совсем понимаю ответ.

1 Ответ

1 голос
/ 18 октября 2019

Если вы укажете аргумент шаблона как int в явном виде, тогда тип параметра func_to_bind станет int&&, то есть типом rvalue-reference. Обратите внимание, что сохраненные аргументы передаются в вызываемый объект как lvalue s на std::bind:

В противном случае обычный хранимый аргумент arg передается ввызываемый объект в качестве аргумента lvalue:

Невозможно привязать lvalue к параметру rvalue-referece, тогда вызов завершится неудачно.

Если вы явно укажете аргумент шаблона как int&тогда тип параметра func_to_bind становится int&, т. е. тип lvalue-reference;lvalue может быть привязан к lvalue-reference, тогда он работает нормально.

И если вы измените тип параметра с func_to_bind на ARGS&, это всегда будет lvalue-reference, по той же причине, что и вышеэто будет работать нормально.

...