#include <iostream>
#include <functional>
#include <memory>
using namespace std;
template<typename ReturnType, typename... Arguments>
class FunctionImplBase
{
public:
virtual ~FunctionImplBase() {}
virtual ReturnType call(Arguments... arguments) = 0;
};
template <typename Callable, typename ReturnType, typename... Arguments>
class FunctionImpl : public FunctionImplBase<ReturnType, Arguments...>
{
public:
explicit FunctionImpl(const Callable& aCallable) : mCallable(aCallable) {}
ReturnType call(Arguments... aArguments) override
{
return mCallable(std::forward<Arguments>(aArguments)...);
}
private:
Callable mCallable;
};
template<typename Signature>
class Function;
template<typename ReturnType, typename... Arguments>
class Function<ReturnType(Arguments...)>
{
public:
Function() {}
template <typename Callable>
explicit Function(Callable aCallable)
: mImpl(std::make_unique<FunctionImpl<Callable, ReturnType, Arguments...>>(aCallable))
{}
template <typename Callable>
Function& operator=(const Callable& aCallable)
{
mImpl = std::make_unique<FunctionImpl<Callable, ReturnType, Arguments...>>(aCallable);
return *this;
}
ReturnType operator()(Arguments... aArguments) const
{
return mImpl->call(std::forward<Arguments>(aArguments)...);
}
private:
std::unique_ptr<FunctionImplBase<ReturnType, Arguments...>> mImpl;
};
struct Foo
{
public:
Foo() {
std::cout << "ctor this:" << this << std::endl;
}
Foo(const Foo &ref) {
std::cout << "copy this:" << this << " ref:" << &ref << std::endl;
}
Foo(Foo &&ref) {
std::cout << "move this:" << this << " ref:" << &ref << std::endl;
}
~Foo() {
std::cout << "dtor this:" << this << std::endl;
}
Foo &operator=(const Foo &rhs) {
cout<<"copy assignment"<<endl;
return (*this);
}
Foo&operator=(Foo&& rhs)
{
cout<<"move assignment"<<endl;
return *this;
}
};
void Bar(Foo f){};
int main()
{
Foo f;
//Function<void(Foo)> func = &Bar; //Error, since explicit
Function<void(Foo)> func (&Bar);
cout<<"invoke +++"<<endl;
func(f);
cout<<"invoke ---"<<endl;
cout<<"std::function invoke ++"<<endl;
std::function<void(Foo)> std_func = &Bar;
std_func(f);
cout<<"std::function invoke --"<<endl;
return 0;
}