diff --git a/applications/test/Tuple2/Test-Tuple2.C b/applications/test/Tuple2/Test-Tuple2.C
index f505554c79b3b5968cd2b2cdff67156536bc213f..31b6ab008dc4fe87fff14cf053f61ed493895698 100644
--- a/applications/test/Tuple2/Test-Tuple2.C
+++ b/applications/test/Tuple2/Test-Tuple2.C
@@ -32,9 +32,39 @@ Description
 #include "label.H"
 #include "scalar.H"
 #include "List.H"
+#include "ops.H"
+#include <functional>
 
 using namespace Foam;
 
+// Test for special comparison operation using compareOp
+// Normal sort on label, reverse sort on scalar
+struct special1
+{
+    typedef Tuple2<label, scalar> type;
+
+    bool operator()(const type& a, const type& b) const
+    {
+        int val = compareOp<label>()(a.first(), b.first());
+        return (val == 0) ? (b.second() < a.second()) : (val < 0);
+    }
+};
+
+
+// Test for special comparison operation using compareOp
+// Normal sort on scalar, reverse sort on label
+struct special2
+{
+    typedef Tuple2<label, scalar> type;
+
+    bool operator()(const type& a, const type& b) const
+    {
+        scalar val = compareOp<scalar>()(a.second(), b.second());
+        return (val == 0) ? (b.first() < a.first()) : (val < 0);
+    }
+};
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // Main program:
 
@@ -46,19 +76,39 @@ int main()
 
     Info<< "tuple: "
         << t2 << " "
-        << t2.first() << " " << t2.second() << endl;
+        << t2.first() << " " << t2.second() << nl;
 
-    List<indexedScalar> list1(10);
-    forAll(list1, i)
+    // As list. Generated so that we have duplicate indices
+    List<indexedScalar> list1(3*4);
+    for (label i = 0; i < 4; ++i)
     {
-        list1[i] = indexedScalar(-i, i*i);
+        const label j = (i+1);
+        const label idx = ((i % 2) ? -1 : 1) * (j);
+
+        list1[i]   = indexedScalar(idx, (j*j));
+        list1[i+4] = indexedScalar(idx, 2*j);    // duplicate index
+        list1[i+8] = indexedScalar(idx+12, 2*j); // duplicate value
     }
 
-    sort(list1);
+    Info<< "Unsorted tuples:" << nl << list1 << nl;
+
+    Foam::sort(list1, std::less<indexedScalar>());
+
+    Info<< "sorted tuples:" << nl << list1 << nl;
+
+    Foam::sort(list1, std::greater<indexedScalar>());
+
+    Info<< "reverse sorted tuples:" << nl << list1 << nl;
+
+    Foam::sort(list1, special1());
+
+    Info<< "special sorted tuples - sort on index, reverse on value:"
+        << nl << list1 << nl;
+
+    Foam::sort(list1, special2());
 
-    Info<< "tuples:" << nl
-        << list1
-        << endl;
+    Info<< "special sorted tuples - sort on value, reverse on index:"
+        << nl << list1 << nl;
 
     Info<< "End\n" << endl;
 
diff --git a/src/OpenFOAM/primitives/Scalar/Scalar.H b/src/OpenFOAM/primitives/Scalar/Scalar.H
index ffb97436b8d78694c5ce62c9a2b2ec42a8c2ece1..c21d99d543102942ac65a17866dd5268f2070c37 100644
--- a/src/OpenFOAM/primitives/Scalar/Scalar.H
+++ b/src/OpenFOAM/primitives/Scalar/Scalar.H
@@ -405,6 +405,28 @@ inline Scalar stabilise(const Scalar s, const Scalar tol)
 
 // Specializations
 
+// Default definition in ops.H
+template<class T> struct compareOp;
+
+//- Compare scalar values
+template<>
+struct compareOp<Scalar>
+{
+    const Scalar tolerance;
+
+    //- Construct with specified tolerance (non-negative value)
+    compareOp(Scalar tol = ScalarVSMALL)
+    :
+        tolerance(tol)
+    {}
+
+    Scalar operator()(const Scalar& a, const Scalar& b) const
+    {
+        return (mag(a - b) <= tolerance) ? 0 : (a - b);
+    }
+};
+
+
 // Default definition in ops.H
 template<class T> struct equalOp;
 
diff --git a/src/OpenFOAM/primitives/ops/ops.H b/src/OpenFOAM/primitives/ops/ops.H
index c179d716b95c5a10e93df5934f3386e791e7e3dc..fd069ad4b066b62ca0b560d6184595635b867d22 100644
--- a/src/OpenFOAM/primitives/ops/ops.H
+++ b/src/OpenFOAM/primitives/ops/ops.H
@@ -216,6 +216,21 @@ WeightedOp(multiply, (weight*y))
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+//- Three-way comparison operation of two parameters,
+//  similar to the \c <=> operator in C++20.
+//
+//  \return a negative value for less, a positive value for greater,
+//      and zero for equal value.
+template<class T>
+struct compareOp
+{
+    int operator()(const T& a, const T& b) const WARNRETURN
+    {
+        return (a < b) ? -1 : (b < a) ? 1 : 0;
+    }
+};
+
+
 //- General get operation to extract the 'name' from an object as a word.
 //  The default implementation uses the 'name()' method commonly used within
 //  OpenFOAM.