为什么std :: function的初始化程序必须是CopyConstructible?

时间:2014-07-09 16:01:32

标签: c++ function templates c++11 constructor

根据http://en.cppreference.com/w/cpp/utility/functional/function/function,初始化器的类型,即形式(5)中的F,应满足CopyConstructible的要求。我不太懂。为什么F只是MoveConstructible不合适?

3 个答案:

答案 0 :(得分:4)

std :: function在内部使用类型擦除,因此即使您使用的特定std :: function对象永远不会被复制,F也必须是CopyConstructible。

简化类型擦除的工作原理:

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()) {}
    //...

};

您必须能够生成Model<F>::clone(),这会强制F为CopyConstructible。

答案 1 :(得分:2)

std::function是CopyConstructible(请参阅文档中的构造函数(3))。如果可以复制所有组件,则只能复制对象。所以包含的F也必须是CopyConstructible。很简单。

答案 2 :(得分:2)

来自@Nevin的例子在显示实现选项方面很有启发性。不过,这里有一些更基本的工作。它不是所使用的特定实现技术的工件。

特别是virtual并不是真正的关键。考虑这种不使用virtual的替代实现(除了在析构函数中)。

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; }
    //...
};

请参阅http://ideone.com/FKFktK了解完整版和示例输出

考虑表达式的值(也在http://ideone.com/FKFktK中):

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

答案不能取决于特定实例的属性或它们的构造方式,在这种情况下甚至没有要查看的实例。可复制性是类型的属性,而不是实例的属性。所以答案必须统一truefalse 在所有情况下。

标准选择is_copy_constructible<function<void()>>::valuetrue。因此,无论std :: function模板的实现内部如何,标准都被迫要求is_copy_constructible<F>::value也是true

如果我们选择is_copy_constructible<function<void()>>::valuefalse,则无论某些特定F本身是否可复制,都不会复制任何实例。