diff --git a/src/polymesh/cursors.hh b/src/polymesh/cursors.hh
index 17a8ee1b7084cd218a8fcf3582c292bc88e3ccb3..4c4a5e9117ca12498d2f57d10c1d61f22a6687fb 100644
--- a/src/polymesh/cursors.hh
+++ b/src/polymesh/cursors.hh
@@ -24,6 +24,10 @@ struct primitive_index
     bool is_invalid() const { return value < 0; }
     static const index_t invalid;
 
+#ifdef POLYMESH_CPP20
+    bool operator==(primitive_index const&) const = default;
+    auto operator<=>(primitive_index const&) const = default;
+#else
     bool operator<(index_t const& rhs) const { return value < rhs.value; }
     bool operator<=(index_t const& rhs) const { return value <= rhs.value; }
     bool operator>(index_t const& rhs) const { return value > rhs.value; }
@@ -32,6 +36,7 @@ struct primitive_index
     bool operator!=(index_t const& rhs) const { return value != rhs.value; }
     bool operator==(handle_t const& rhs) const { return value == rhs.idx.value; }
     bool operator!=(handle_t const& rhs) const { return value != rhs.idx.value; }
+#endif
 
     explicit operator int() const { return value; }
 
@@ -73,10 +78,14 @@ struct primitive_handle
     primitive_handle() = default;
     primitive_handle(Mesh const* mesh, index_t idx) : mesh(mesh), idx(idx) {}
 
-    bool operator==(index_t const& rhs) const { return idx == rhs; }
-    bool operator!=(index_t const& rhs) const { return idx != rhs; }
+#ifdef POLYMESH_CPP20
+    bool operator==(primitive_handle const&) const = default;
+#else
     bool operator==(handle_t const& rhs) const { return mesh == rhs.mesh && idx == rhs.idx; }
     bool operator!=(handle_t const& rhs) const { return mesh != rhs.mesh || idx != rhs.idx; }
+#endif
+    bool operator==(index_t const& rhs) const { return idx == rhs; }
+    bool operator!=(index_t const& rhs) const { return idx != rhs; }
 
     explicit operator int() const { return (int)idx; }
     operator index_t() const { return idx; }
diff --git a/src/polymesh/iterators.hh b/src/polymesh/iterators.hh
index 75fcac90513a40fc5e63a373531860f37321527d..710931cdb8e3ec549fb2c27637e4edf048e976bb 100644
--- a/src/polymesh/iterators.hh
+++ b/src/polymesh/iterators.hh
@@ -149,7 +149,7 @@ struct primitive_circulator : smart_iterator<this_t>
 
     primitive_circulator(halfedge_handle h, bool at_begin = true) : handle(h), end(h), at_begin(at_begin) {}
 
-    bool is_valid() const { return at_begin || handle != end; }
+    bool is_valid() const { return at_begin || handle.idx != end; }
 };
 
 struct face_vertex_circulator : primitive_circulator<face_vertex_circulator>
@@ -195,7 +195,7 @@ struct face_face_circulator : primitive_circulator<face_face_circulator>
         do // skip invalid faces
         {
             handle = handle.next();
-        } while (handle != end && handle.opposite_face().is_invalid());
+        } while (handle.idx != end && handle.opposite_face().is_invalid());
         at_begin = false;
     }
 };
@@ -243,7 +243,7 @@ struct vertex_face_circulator : primitive_circulator<vertex_face_circulator>
         do // skip invalid faces
         {
             handle = handle.prev().opposite();
-        } while (handle != end && handle.face().is_invalid());
+        } while (handle.idx != end && handle.face().is_invalid());
         at_begin = false;
     }
 };
diff --git a/src/polymesh/macros.hh b/src/polymesh/macros.hh
index be8d510a5c33b4e2a1ac60e17c0ed4eac5a5848c..9121a3b652d577a121c3cb889b527df8cda3946c 100644
--- a/src/polymesh/macros.hh
+++ b/src/polymesh/macros.hh
@@ -17,6 +17,10 @@
 #error "Unknown compiler"
 #endif
 
+#if __cplusplus >= 202002L
+#define POLYMESH_CPP20
+#endif
+
 
 // =========
 // compiler specific builtins
diff --git a/src/polymesh/tmp.hh b/src/polymesh/tmp.hh
index a0454f8d0111503c3b6a9a21e716d3e92d5042aa..953303dbfa8b5fa5d0949971396e17ae3a3d95a9 100644
--- a/src/polymesh/tmp.hh
+++ b/src/polymesh/tmp.hh
@@ -3,6 +3,12 @@
 #include <cstddef>
 #include <utility>
 
+#include <polymesh/macros.hh>
+
+#ifdef POLYMESH_CPP20
+#include <compare>
+#endif
+
 namespace polymesh
 {
 // small template metaprogramming