Why the initializer of std::function has to be CopyConstructible?

According to http://en.cppreference.com/w/cpp/utility/functional/function/function, the type of the initializer, i.e., F in form (5), should meet the requirements of CopyConstructible. I don't quite get this. Why is it not OK for F to be just MoveConstructible?


std::function uses type erasure internally, so F has to be CopyConstructible even if the particular std::function object you are using is never copied.

A simplification on how type erasure works:

class Function
{
    struct Concept {
        virtual ~Concept() = default;
        virtual Concept* clone() const = 0;
        //...
    }

    template<typename F>
    struct Model final : Concept {

        explicit Model(F f) : data(std::move(f)) {}
        Model* clone() const override { return new Model(*this); }
        //...

        F data;
    };

    std::unique_ptr<Concept> object;

public:
    template<typename F>
    explicit Function(F f) : object(new Model<F>(std::move(f))) {}

    Function(Function const& that) : object(that.object->clone()) {}
    //...

};

You have to be able to generate Model<F>::clone(), which forces F to be CopyConstructible.


The example from @Nevin is illuminating in terms of showing an implementation option. Still, there is something more fundamental at work here. It is not an artifact of the particular implementation technique used.

In particular, the virtual is not really the key here. Consider this alternative implementation that does not use virtual (other than at the destructor).

class Function
{
  struct Concept {
    typedef Concept * (*cloneFunType)(const Concept *);
    cloneFunType m_cloneFun = nullptr;    
    virtual ~Concept() = default;
  };

  template<typename F> struct Model final : Concept {
    static Concept* clone(const Concept *c)  { 
      return new Model(static_cast<const Model*>(c)->data); }

    explicit Model(F &&f) : data(move(f)) { this->m_cloneFun = &Model::clone;}

    explicit Model(const F &f) : data(f) { this->m_cloneFun = &Model::clone; }

    F data;
  };

  Concept* object;

public:
  ~Function() { delete object; }

  template<typename F> explicit Function(F&& f) 
    : object(new Model<typename remove_reference<F>::type>(forward<F>(f))) {} 

  Function(Function const& that) 
    : object((*(that.object->m_cloneFun))(that.object)) {}

  Function(Function && that) : object(that.object) { that.object = nullptr; }
    //...
};

see http://ideone.com/FKFktK for the full version and example output

Consider what is the value of the expression (also in http://ideone.com/FKFktK):

is_copy_constructible<function<void()>>::value

The answer cannot depend on the properties of specific instances or how they were constructed, there isn't even an instance to look at in this case. Copyability is a property of a type, not of an instance. So the answer has to be uniformly true or false across all instances.

The standard chose is_copy_constructible<function<void()>>::value to be true. As a consequence, the standard is forced to require that is_copy_constructible<F>::value also be true regardless of implementation internals of the std::function template.

If we chose is_copy_constructible<function<void()>>::value to be false, then no instance would be copyable regardless of whether some specific F itself was copyable.