#include <iostream>
#include <memory>
 
template <typename T>
struct propagating_unique_ptr : std::unique_ptr<T> {
    using std::unique_ptr<T>::unique_ptr;
    using std::unique_ptr<T>::operator =;
 
    const T *get() const noexcept {
        return std::unique_ptr<T>::get();
    }
    T *get() noexcept {
        return std::unique_ptr<T>::get();
    }
 
    const T &operator *() const noexcept {
        return std::unique_ptr<T>::operator *();
    }
    T &operator *() noexcept {
        return std::unique_ptr<T>::operator *();
    }
 
    const T *operator -> () const noexcept {
        return std::unique_ptr<T>::get();
    }
    T *operator -> () noexcept {
        return std::unique_ptr<T>::get();
    }
}; 
 
struct foo {
    foo() : value_ptr_(std::make_unique<int>(3)) {}
    void increment() {
        ++(*value_ptr_); // OK
    }
    int get_value() const {
        return *value_ptr_;
    }
    propagating_unique_ptr<int> value_ptr_;
};
 
int main() {
    foo my_foo;
    std::cout << my_foo.get_value() << std::endl;
    my_foo.increment(); // OK
    std::cout << my_foo.get_value() << std::endl;
}