mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-21 22:04:56 -06:00
New Core Tutorial
git-svn-id: svn://ultimatepp.org/upp/trunk@10538 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
dd88feaf2e
commit
6c22e727de
37 changed files with 3125 additions and 0 deletions
134
tutorial/CoreTutorial/Compare.cpp
Normal file
134
tutorial/CoreTutorial/Compare.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include "Tutorial.h"
|
||||
|
||||
void ComparableTutorial()
|
||||
{
|
||||
/// .SgnCompare and CombineCompare
|
||||
|
||||
/// Traditional approach of C language of representing comparison results was 3-state:
|
||||
/// comparing a and b results in negative value (if a < b), zero (if a == b) or positive
|
||||
/// value (a > b). In C++ standard library, comparisons are usually represented with `bool`
|
||||
/// predicates.
|
||||
|
||||
/// However, with `bool` predicate it becomes somewhat more difficult to provide
|
||||
/// comparisons for composite types:
|
||||
|
||||
struct Foo {
|
||||
String a;
|
||||
int b;
|
||||
int c;
|
||||
|
||||
// we want to order Foo instances by a first, then b, then c
|
||||
|
||||
bool operator<(const Foo& x) const {
|
||||
return a < x.a ? true
|
||||
: a == x.a ? b < x.b ? true
|
||||
: b == x.b ? false
|
||||
: c < x.c
|
||||
: false;
|
||||
}
|
||||
};
|
||||
|
||||
/// U++ provides standard function `SgnCompare`, which returns negative value/zero/positive
|
||||
/// in "C style":
|
||||
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
DUMP(SgnCompare(a, b));
|
||||
DUMP(SgnCompare(b, a));
|
||||
DUMP(SgnCompare(a, a));
|
||||
|
||||
/// Default implementation of `SgnCompare` calls `Compare` method of value:
|
||||
|
||||
struct MyClass {
|
||||
int val;
|
||||
|
||||
int Compare(const MyClass& x) const { return SgnCompare(val, x.val); }
|
||||
};
|
||||
|
||||
/// `SgnCompare` is now defined for `MyClass`:
|
||||
|
||||
MyClass u, v;
|
||||
u.val = 1;
|
||||
v.val = 2;
|
||||
|
||||
DUMP(SgnCompare(u, v));
|
||||
DUMP(SgnCompare(v, u));
|
||||
DUMP(SgnCompare(v, v));
|
||||
|
||||
/// Now getting back to `Foo`, with `SgnCompare` `operator<` becomes much less difficult:
|
||||
|
||||
struct Foo2 {
|
||||
String a;
|
||||
int b;
|
||||
int c;
|
||||
|
||||
bool operator<(const Foo2& x) const {
|
||||
int q = SgnCompare(a, x.a);
|
||||
if(q) return q < 0;
|
||||
q = SgnCompare(b, x.b);
|
||||
if(q) return q < 0;
|
||||
q = SgnCompare(c, x.c);
|
||||
return q < 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// Alternatively, it is possible to define just `Compare` method and use `Comparable`
|
||||
/// ^https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern:CRTP idiom^ to
|
||||
/// define all relation operators:
|
||||
|
||||
struct Foo3 : Comparable<Foo3> {
|
||||
String a;
|
||||
int b;
|
||||
int c;
|
||||
|
||||
int Compare(const Foo3& x) const {
|
||||
int q = SgnCompare(a, x.a);
|
||||
if(q) return q;
|
||||
q = SgnCompare(b, x.b);
|
||||
if(q) return q;
|
||||
return SgnCompare(c, x.c);
|
||||
}
|
||||
};
|
||||
|
||||
Foo3 m, n;
|
||||
m.a = "A";
|
||||
m.b = 1;
|
||||
m.c = 2;
|
||||
n.a = "A";
|
||||
n.b = 1;
|
||||
n.c = 3;
|
||||
|
||||
DUMP(m < n);
|
||||
DUMP(m == n);
|
||||
DUMP(m != n);
|
||||
DUMP(SgnCompare(m, n));
|
||||
|
||||
/// While the content of `Compare` method is trivial, it can be further simplified using
|
||||
/// `CombineCompare` helper class:
|
||||
|
||||
struct Foo4 : Comparable<Foo4> {
|
||||
String a;
|
||||
int b;
|
||||
int c;
|
||||
|
||||
int Compare(const Foo4& x) const {
|
||||
return CombineCompare(a, x.a)(b, x.b)(c, x.c);
|
||||
}
|
||||
};
|
||||
|
||||
Foo4 o, p;
|
||||
o.a = "A";
|
||||
o.b = 1;
|
||||
o.c = 2;
|
||||
p.a = "A";
|
||||
p.b = 1;
|
||||
p.c = 3;
|
||||
|
||||
DUMP(o < p);
|
||||
DUMP(o == p);
|
||||
DUMP(o != p);
|
||||
DUMP(SgnCompare(o, p));
|
||||
|
||||
///
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue