Search code examples
c++c++14variadic-templatesstdbind

How to bind reference of non-movable object in variadic template arguments?


In the following minimal example:

#include <iostream>
#include <functional>

class Non_movable{
public:
  Non_movable(void){ }
  Non_movable(const Non_movable& other) = delete;/* Copy constructor */
  Non_movable(Non_movable&& other) = delete; /* Move constructor */
  Non_movable& operator=(const Non_movable& other) = delete; /* Copy assignment */
  Non_movable& operator=(Non_movable&& other) = delete; /* Move assignment */
};

template<typename ...T>
std::function<void(int)> make_bound(T... args, std::function<void(T..., int)> fun){
  return std::bind(fun, args..., std::placeholders::_1);
}

int main(int argc, char** agrs){
  Non_movable no_move;
  make_bound<Non_movable&>(no_move, [](Non_movable&, int num){
    std::cout << num << std::endl;
  })(6);
  return 0;
}

There is a big wall of compile errors upon compiling on --std=c++14, which is understandable, since each argument in the variadic template should be dound with the std::ref keyword to make it compilable.

Interestingly, if the gang of five becomes the default, instead of deleted, compile passes, and the function call behaves as if the template was called with an lvalue of Non_movable why is that?

Is there a way to make this compilable with variadic templates?


Solution

  • In the parameter pack expansion you can write any pattern including at least one parameter pack, see https://en.cppreference.com/w/cpp/language/parameter_pack. This means that in your make_bound function you can just write

    return std::bind(fun, std::ref(args)..., std::placeholders::_1);
    

    Please find your adapted minimal example here: https://onlinegdb.com/XhTBHpW9X

    Besides that, your no_move object is an lvalue, so it's passed to make_bound as lvalue, regardless of if the copy/move constructors and assignment operators are defaulted or deleted.