c++standardsstd-function

Why does C++ allow std::function assignments to imply an object copy?


My question concerns the line of code below marked with the // WHY??? comment.

Below is a toy example of some code I was expecting to break: a std::function variable is assigned a function pointer whose parameters almost match, but differ in const and &. It didn't break. I've figured out why it works -- there's a copy constructor call added by the compiler that I didn't expect.

My question is: why does C++ allow this case? What is the use-case that made the C++ committee decide this should work (as opposed to the compiler rejecting this assignment)?

#include <memory>
#include <functional>
#include <iostream>

class Thing {
  public:
    Thing(int count) : count_(count) {}
    int count_;
};

typedef std::function<void(const Thing&)> ConstByRefFunction;

void DoThingByValue(Thing event) { event.count_ += 5; }

int main() {
  Thing thing(95);
  ConstByRefFunction func = DoThingByValue; // WHY???
  // The following line copies thing even though anyone looking at
  // the signature of ConstByRefFunction would expect it not to copy.
  func(thing);
  std::cout << thing.count_ << std::endl; // still 95
  return 0;
}

Solution

  • The signature you specify in the std::function template is the signature used for the std::function's operator() overload, NOT the signature used for the target that the operator() calls.

    You can assign any target to std::function which is Callable using the parameters of the operator(). In your example, DoThingByValue() is an acceptable target because a const Thing& parameter can be passed by value to a Thing parameter (thus invoking the Thing copy constructor), no different than if you were doing something like this:

    void DoThingByValue(Thing event) {
      ...
    }
    
    void DoThingByConstRef(const Thing &event) {
      DoThingByValue(event); // <-- COPY HERE
    }