Index: uspace/lib/cpp/include/__bits/thread/future_common.hpp
===================================================================
--- uspace/lib/cpp/include/__bits/thread/future_common.hpp	(revision a5520443f7c091e0dc2007a854c8f75a1f131520)
+++ uspace/lib/cpp/include/__bits/thread/future_common.hpp	(revision a6c3bf33625d79d2777ad85a32afc7eb8aba9e2c)
@@ -30,4 +30,5 @@
 #define LIBCPP_BITS_THREAD_FUTURE_COMMON
 
+#include <__bits/aux.hpp>
 #include <system_error>
 #include <stdexcept>
@@ -82,4 +83,40 @@
             error_code code_;
     };
+
+    namespace aux
+    {
+        /**
+         * Auxilliary metafunctions that let us avoid
+         * specializations in some cases. They represent
+         * the inner stored type and the return type of
+         * the get() member function, respectively.
+         */
+
+        template<class T>
+        struct future_inner: aux::type_is<T>
+        { /* DUMMY BODY */ };
+
+        template<class T>
+        struct future_inner<T&>: aux::type_is<T*>
+        { /* DUMMY BODY */ };
+
+        template<class T>
+        using future_inner_t = typename future_inner<T>::type;
+
+        template<class T>
+        struct future_return: aux::type_is<const T&>
+        { /* DUMMY BODY */ };
+
+        template<class T>
+        struct future_return<T&>: aux::type_is<T&>
+        { /* DUMMY BODY */ };
+
+        template<>
+        struct future_return<void>: aux::type_is<void>
+        { /* DUMMY BODY */ };
+
+        template<class T>
+        using future_return_t = typename future_return<T>::type;
+    }
 }
 
Index: uspace/lib/cpp/include/__bits/thread/shared_future.hpp
===================================================================
--- uspace/lib/cpp/include/__bits/thread/shared_future.hpp	(revision a5520443f7c091e0dc2007a854c8f75a1f131520)
+++ uspace/lib/cpp/include/__bits/thread/shared_future.hpp	(revision a6c3bf33625d79d2777ad85a32afc7eb8aba9e2c)
@@ -31,4 +31,6 @@
 
 #include <__bits/thread/future.hpp>
+#include <__bits/thread/future_common.hpp>
+#include <type_traits>
 
 /**
@@ -49,5 +51,5 @@
 
     template<class R>
-    class shared_future: public aux::future_base<R>
+    class shared_future: public aux::future_base<aux::future_inner_t<R>>
     {
         public:
@@ -59,5 +61,5 @@
 
             shared_future(future<R>&& rhs)
-                : aux::future_base<R>{move(rhs.state_)}
+                : aux::future_base<aux::future_inner_t<R>>{move(rhs.state_)}
             {
                 rhs.state_ = nullptr;
@@ -68,5 +70,5 @@
             shared_future& operator=(shared_future&&) noexcept = default;
 
-            const R& get() const
+            aux::future_return_t<R> get() const
             {
                 assert(this->state_);
@@ -77,70 +79,20 @@
                     this->state_->throw_stored_exception();
 
-                return move(this->state_->get());
-            }
-    };
+                /**
+                 * Using constexpr if and the future_inner and future_result
+                 * metafunctions we can actually avoid having to create specializations
+                 * for R& and void in this case.
+                 */
+                if constexpr (!is_same_v<R, void>)
+                {
+                    if constexpr (is_reference_v<R>)
+                    {
+                        assert(this->state_->get());
 
-    template<class R>
-    class shared_future<R&>: public aux::future_base<R*>
-    {
-        public:
-            shared_future() noexcept = default;
-
-            shared_future(const shared_future&) = default;
-
-            shared_future(shared_future&&) noexcept = default;
-
-            shared_future(future<R&>&& rhs)
-                : aux::future_base<R*>{move(rhs.state_)}
-            {
-                rhs.state_ = nullptr;
-            }
-
-            shared_future& operator=(const shared_future&) = default;
-
-            shared_future& operator=(shared_future&&) noexcept = default;
-
-            R& get() const
-            {
-                assert(this->state_);
-
-                this->wait();
-
-                if (this->state_->has_exception())
-                    this->state_->throw_stored_exception();
-
-                assert(this->state_->get());
-                return *this->state_->get();
-            }
-    };
-
-    template<>
-    class shared_future<void>: public aux::future_base<void>
-    {
-        public:
-            shared_future() noexcept = default;
-
-            shared_future(const shared_future&) = default;
-
-            shared_future(shared_future&&) noexcept = default;
-
-            shared_future(future<void>&& rhs)
-                : aux::future_base<void>{move(rhs.state_)}
-            {
-                rhs.state_ = nullptr;
-            }
-
-            shared_future& operator=(const shared_future&) = default;
-
-            shared_future& operator=(shared_future&&) noexcept = default;
-
-            void get() const
-            {
-                assert(this->state_);
-
-                this->wait();
-
-                if (this->state_->has_exception())
-                    this->state_->throw_stored_exception();
+                        return *this->state_->get();
+                    }
+                    else
+                        return this->state_->get();
+                }
             }
     };
