Index: uspace/lib/cpp/include/impl/tuple.hpp
===================================================================
--- uspace/lib/cpp/include/impl/tuple.hpp	(revision 78d739d3d1485b232e1c906ade4120a538866dbf)
+++ uspace/lib/cpp/include/impl/tuple.hpp	(revision 55cd8299a72ca04832bff65f238be1619989a9a2)
@@ -288,5 +288,5 @@
     namespace aux
     {
-        template<size_t I>
+        template<size_t I, size_t N>
         struct tuple_ops
         {
@@ -296,5 +296,5 @@
                 get<I>(forward<T>(lhs)) = get<I>(forward<U>(rhs));
 
-                tuple_ops<I - 1>::assign(forward<T>(lhs), forward<U>(rhs));
+                tuple_ops<I + 1, N>::assign(forward<T>(lhs), forward<U>(rhs));
             }
 
@@ -304,22 +304,28 @@
                 std::swap(get<I>(lhs), get<I>(rhs));
 
-                tuple_ops<I - 1>::swap(lhs, rhs);
-            }
-
-            // TODO: for rel ops we will need this to be ascending, not descending
-            template<class T, class U>
-            static bool eq(const T& lhs, const T& rhs)
-            {
-                return (get<I>(lhs) == get<I>(rhs)) && tuple_ops<I - 1>::eq(lhs, rhs);
-            }
-        };
-
-        template<>
-        struct tuple_ops<0>
+                tuple_ops<I + 1, N>::swap(lhs, rhs);
+            }
+
+            template<class T, class U>
+            static bool eq(const T& lhs, const U& rhs)
+            {
+                return (get<I>(lhs) == get<I>(rhs)) && tuple_ops<I + 1, N>::eq(lhs, rhs);
+            }
+
+            template<class T, class U>
+            static bool lt(const T& lhs, const U& rhs)
+            {
+                return (get<I>(lhs) < get<I>(rhs)) ||
+                    (!(get<I>(rhs) < get<I>(lhs)) && tuple_ops<I + 1, N>::lt(lhs, rhs));
+            }
+        };
+
+        template<size_t N>
+        struct tuple_ops<N, N>
         {
             template<class T, class U>
             static void assign(T&& lhs, U&& rhs)
             {
-                get<0>(forward<T>(lhs)) = get<0>(forward<U>(rhs));
+                get<N>(forward<T>(lhs)) = get<N>(forward<U>(rhs));
             }
 
@@ -327,5 +333,17 @@
             static void swap(T& lhs, U& rhs)
             {
-                std::swap(get<0>(lhs), get<0>(rhs));
+                std::swap(get<N>(lhs), get<N>(rhs));
+            }
+
+            template<class T, class U>
+            static bool eq(const T& lhs, const U& rhs)
+            {
+                return get<N>(lhs) == get<N>(rhs);
+            }
+
+            template<class T, class U>
+            static bool lt(const T& lhs, const U& rhs)
+            {
+                return get<N>(lhs) < get<N>(rhs);
             }
         };
@@ -374,5 +392,6 @@
             //{ /* DUMMY BODY */ }
 
-            template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
+            // TODO: pair related construction and assignment needs convertibility, not size
+            template<class U1, class U2>
             constexpr tuple(const pair<U1, U2>& p)
                 : base_t{}
@@ -382,5 +401,5 @@
             }
 
-            template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
+            template<class U1, class U2>
             constexpr tuple(pair<U1, U2>&& p)
                 : base_t{}
@@ -398,5 +417,5 @@
             tuple& operator=(const tuple& other)
             {
-                aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, other);
+                aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, other);
 
                 return *this;
@@ -405,5 +424,5 @@
             tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment<Ts...>::value)
             {
-                aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, forward<tuple>(other));
+                aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, forward<tuple>(other));
 
                 return *this;
@@ -413,5 +432,5 @@
             tuple& operator=(const tuple<Us...>& other)
             {
-                aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, other);
+                aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, other);
 
                 return *this;
@@ -421,10 +440,10 @@
             tuple& operator=(tuple<Us...>&& other)
             {
-                aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, forward<Us>(other)...);
+                aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, forward<Us>(other)...);
 
                 return *this;
             }
 
-            template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
+            template<class U1, class U2>
             tuple& operator=(const pair<U1, U2>& p)
             {
@@ -433,5 +452,5 @@
             }
 
-            template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
+            template<class U1, class U2>
             tuple& operator=(pair<U1, U2>&& p)
             {
@@ -446,5 +465,5 @@
             void swap(tuple& other) noexcept(aux::tuple_noexcept_swap<Ts...>::value)
             {
-                aux::tuple_ops<sizeof...(Ts) - 1>::swap(*this, other);
+                aux::tuple_ops<0, sizeof...(Ts) - 1>::swap(*this, other);
             }
     };
@@ -455,20 +474,44 @@
 
     template<class... Ts, class... Us>
-    constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
+    constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
+    {
+        if constexpr (sizeof...(Ts) == 0)
+            return true;
+        else
+            return aux::tuple_ops<0, sizeof...(Ts) - 1>::eq(lhs, rhs);
+    }
 
     template<class... Ts, class... Us>
-    constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
+    constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
+    {
+        if constexpr (sizeof...(Ts) == 0)
+            return false;
+        else
+            return aux::tuple_ops<0, sizeof...(Ts) - 1>::lt(lhs, rhs);
+    }
 
     template<class... Ts, class... Us>
-    constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
+    constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
+    {
+        return !(lhs == rhs);
+    }
 
     template<class... Ts, class... Us>
-    constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
+    constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
+    {
+        return rhs < lhs;
+    }
 
     template<class... Ts, class... Us>
-    constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
+    constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
+    {
+        return !(rhs < lhs);
+    }
 
     template<class... Ts, class... Us>
-    constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
+    constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
+    {
+        return !(lhs < rhs);
+    }
 
     /**
