#include <utility>
#include <cstdio>
#include <cmath>

template<typename Fn>
class Action {
    Fn* function_ptr;
    
public:
    Action() noexcept : function_ptr(nullptr) {
    }    
    Action(std::nullptr_t) noexcept : function_ptr(nullptr) {
    }    
    Action(const Action& other) : function_ptr(other.function_ptr) {
    }    
    Action(Fn f) : function_ptr(f) {
    }

    Action& operator=(const Action& other) {
        return (function_ptr = other.function_ptr, *this);
    }            
    Action& operator=(std::nullptr_t ) {
        return (function_ptr = nullptr, *this);
    }    
    Action& operator=(Fn f) {
        return (function_ptr = f, *this);
    }
    
    template<typename... Params>
    auto operator()(Params&&... params) {
        return function_ptr(std::forward<Params>(params)...);
    }
};
        
void test(int i) {
    printf("The given parameter is: %d\n", i);
}

int main() {
    Action<decltype(printf)> pf_1;
    pf_1 = nullptr;    
    pf_1 = printf;
    
    Action<decltype(printf)> pf_2(pf_1);
    pf_2("The value of Pi is: %.5f\n", M_PI);
    
    Action<decltype(test)> test_fn(test);
    test_fn(12);
    
    return 0;
}