1

Here i have small piece of code and it compiles and works just fine (at least with my GCC 7.3.0 and 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"));
}

The part that i don't understand is this line:

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

Why does compiler require to use references as template type parameters? If i remove reference from int like this:

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

It won't compile. Also if i change func_to_bind signature to this:

bool func_to_bind(ARGS& ... args) const

It will compile just fine even with missing reference. Could anyone explain what's exactly going on here? I also did some search and found this question: How to combine std::bind(), variadic templates, and perfect forwarding?

But i don't completely understand the answer.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
toozyfuzzy
  • 1,080
  • 1
  • 9
  • 20
  • 3
    FWIW you don't need to use `std::bind`. Lambdas generally make the code easier to write and allow you to avoid having to specify template parameters as it can use overload resolution and template argument deduction for you. `func_obj` can be rewritten as `func_obj = [this](auto&&.. args){ return func_to_bind(42, args...); };` – NathanOliver Oct 18 '19 at 14:41
  • It's all good but all I can use is C++ 11 which doesn't have generic parameters for lambdas – toozyfuzzy Oct 18 '19 at 15:40

1 Answers1

1

If you specify the template argument as int explicitly, then the parameter type of func_to_bind would become int&&, i.e. an rvalue-reference type. Note that the stored arguments are passed to the invokable object as lvalues by std::bind:

Otherwise, the ordinary stored argument arg is passed to the invokable object as lvalue argument:

The lvalue can't be bound to the rvalue-referece parameter then invocation fails.

If you specify the template argument as int& explicitly, then the parameter type of func_to_bind becomes int&, i.e. an lvalue-reference type; lvalue could be bound to lvalue-reference then it works fine.

And if you change the parameter type of func_to_bind to ARGS&, it'll be always an lvalue-reference, for the same reason above it'll work fine.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405