std::function alternative with no dependencies An alternative to std::function for when compile time is more important than runtime performance. Doesn't pull in any headers.

(#include &lt;functional&gt; pulls in 19k lines of code.)

This satisfies my needs, but I'm curious how it could be improved (without adding any dependencies).

template&lt;typename&gt;
class func;

// Alternative to std::function for when compile time is
// more important than runtime performance. Doesn't pull in
// any headers.
template&lt;typename Result, typename... Arguments&gt;
class func&lt;Result (Arguments...)&gt; {

  struct holder {
    virtual ~holder() {}
    virtual Result call(Arguments...) = 0;
    virtual holder* clone() = 0;
  };

  template&lt;typename Lambda&gt;
  struct lambda_holder : public holder {
    virtual ~lambda_holder() {}
    Lambda lambda;
    lambda_holder(Lambda l) : lambda(l) { }
    Result call(Arguments... args) override {
      return lambda(args...);
    }
    holder* clone() override {
      return new lambda_holder&lt;Lambda&gt;(lambda);
    }
  };

public:

  func() { }

  func(const func&amp; f) {
    holder = f.holder-&gt;clone();
  }

  func&amp; operator=(const func&amp; f) {
    if(holder) { delete holder; }
    holder = f.holder ? f.holder-&gt;clone() : nullptr;
    return *this;
  }

  // Create from a lambda.
  template&lt;class F&gt;
  func(F f) {
    holder = new lambda_holder&lt;F&gt;{f};
  }

  ~func() {
    if(holder) { delete holder; }
  }

  Result operator()(Arguments... args) const {
    assert(holder);
    return holder-&gt;call(args...);
  }

  operator bool() const {
    return holder;
  }

private:

  holder *holder = nullptr;

};
Self-assignment may be expensive, but it should be a no-op instead of UB. I suggest copy-and-swap.
Omitting move-semantics will most certainly cost you.
Your naming of the internal class suggests all callables are lambdas. Not true!
You cannot store any move-only callables. Admittedly std::function is also crippled in that respect. Just throw an exception if the non-copyable object needs to be copied.
If your function has return-type void, it should simply discard the callables return-value. You don't.
std::function throws an exception if empty when called. Using assert() is less than a pale imitation.
delete p; if p is a null pointer is a no-op. No need to double-check.
Conversion to bool should be explicit. Otherwise, conversion to any arithmetic type can happen.
As you said, yours is less efficient. That's especially the case when std::function benefits from mandatory small-object-optimization.
You don't use SFINAE when creating from a callable. That can be inconvenient.