The lengths some go to avoid just using a bog-standard virtual function.
I actually used the "virtual function" approach earlier in SumatraPDF.
The problem with that is that for every type of callback you need to create a base class and then create a derived function for every unique use.
That's a lot of classes to write.
Consider this (from memory so please ignore syntax errors, if any):
class ThreadBase { virtual void Run(); // ... } class MyThread : ThreadBase { MyData* myData; void Run() override; // ... } StartThread(new MyThread());
HANDLE StartThread(const Func0&, const char* threadName = nullptr); auto fn = MkFunc0(InstallerThread, &gCliNew); StartThread(fn, "InstallerThread");
This is replaced by Func0 or Func1<T>. No new classes, much less typing. And less typing is better programming ergonomics.
std::function arguably has slightly better ergonomics but higher cost on 3 dimension (runtime, compilation time, understandability).
In retrospect Func0 and Func1 seem trivial but it took me years of trying other approaches to arrive at insight needed to create them.
I actually used the "virtual function" approach earlier in SumatraPDF.
The problem with that is that for every type of callback you need to create a base class and then create a derived function for every unique use.
That's a lot of classes to write.
Consider this (from memory so please ignore syntax errors, if any):
compared to: I would have to create a base class for every unique type of the callback and then for every caller possibly a new class deriving.This is replaced by Func0 or Func1<T>. No new classes, much less typing. And less typing is better programming ergonomics.
std::function arguably has slightly better ergonomics but higher cost on 3 dimension (runtime, compilation time, understandability).
In retrospect Func0 and Func1 seem trivial but it took me years of trying other approaches to arrive at insight needed to create them.