I am reading the "Templates and Generic Programming" part in C++ Primer(5th Edition) but I got confused by some of the stuff there.
When talking about "Writing Type-Independent Code" at P655 & P656, the author stated that
"The tests in the body use only < comparisons " , because "by writing the code using only the < operator, we reduce the requirements on types that can be used with our compare function. Those types must support <, but they need not also support >." .
Are there any types that support < but not > ? If so, why < has the superiority over > ? I have searched on Google for some time but I failed to get the answer. Could anybody give me some examples or some referral links?
If so, why < has the superiority over >?
Mere convention. The character '<' comes first in ASCII, and less-than over a partially-ordered set is a primitive from which the comparisons may be constructed (i.e., the set is partitioned into equivalence groups).
If we have a, b, and operator <:
a < b if operator <( a, b )
a > b if operator <( b, a )
a ≤ b if ! operator <( b, a )
a = b if ! operator <( a, b ) && ! operator <( b, a )
etc.
C++ has a number of such conventions which are used to describe how types behave. These are often called concepts, and an upcoming language extension, capital-C Concepts, will allow you to query and specify such things as whether the less-than operator defines a partial ordering.
Are there any types that support < but not >?
Yes, many. The convention is to define operator < and then forget about > because it would be redundant. You can use something like std::relops to automatically define > in terms of <, but overall it's easier just to avoid writing the > operator in the first place.
All the parts of the standard library that depend on ordering, such as std::sort and std::map, will never use >.
In some languages (like Haskell), there is this concept of minimal complete definition. For example, if you have defined a new class (e.g. for rational numbers) with a total order, it is sufficient to define the <= operator. The other operators can be (in some cases automatically) defined in terms of the minimal definition:
x > y can be defined as ! (x <= y)
x == y can be defined as x <= y && y <= x
x >= y can be defined as x > y || x == y
x < y can be defined as ! (x >= y)
In this case, the minimal definition has only one operator. In general, you only have to define the operators in a minimal complete definition, and doing so will reduce redundant definition of the other operators that can be "inferred". Implementing only the minimal definition also reduces the chances that you introduce errors or inconsistency while implementing the non-essential operators (like >) in your case. The point is that it is often beneficial to implement a minimal set of operators.
Regarding why < is preferred over >, I think this is rather a matter of choice and convention. Strictly speaking, one could have chosen to implement any minimal definition. In the case of total order types, each of {<=} and {>=} is minimal complete set. So those types must support one of these sets, but they need not also support the rest of them.
There are cases where a type might use operator < for no other reason than to use as a sorting key. It's not necessarily that the order is meaningful, it's just to support the very templated APIs that you're describing. For instance, std::map will keep all its elements sorted based on operator < unless you give it a different predicate. You may not care exactly what that order is, you just want to be able to have fast (O(log n)) lookups. The order may be completely meaningless to the class otherwise. (In that case, you'd probably want a free function binary version of operator < instead of making it a member, or provide an explicit predicate).
If other operations are meaningful to your class, then by all means implement them. It will make your users' lives much simpler. And you can always implement them in terms of operator < if it simplifies the logic.
The only reason I can think of that they used operator < instead of operator > is that it makes the order a bit more natural (assuming your language is written left-to-right). If you store the integers 1 through 5 in a map, they'll be ordered 1 < 2 < 3 < 4 < 5. So in the case of operator <(T left, T right) if the predicate returns true, the left operand will be more literally "to the left" of the right operand.
And after one more pass over the text you quoted, it sounds to me they're speaking more about the person writing the algorithm that uses operator < rather than the person writing the class that implements operator <. If you're writing an algorithm that needs to work with other people's code, and you want them to give you a way to order their elements, you should only require operator <. The point is to simplify work at the "client" side.
Related
Definition:
Let < be a binary relation where a < b means "a is less than b".
Let > be a binary relation where a > b means "a is greater than b".
So, we assume < and > have meanings we usually use in a daily life. Though, in some programming languages (e.g. C++), we can overload them to give them different definitions, hereafter we don't think about that.
Context:
As far I read mathematical definition of strict weak ordering (e.g. Wikipedia), I think both < and > satify it. However, all examples I saw in many websites refer only to <. There is even a website which says
what they roughly mean is that a Strict Weak Ordering has to behave the way that "less than" behaves: if a is less than b then b is not less than a, if a is less than b and b is less than c then a is less than c, and so on.
Also, in N4140 (C++14 International Standard), strict weak ordering is defines as
(§25.4-4) If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp and equiv both be transitive relations
where comp is defined as
(§25.4-2) Compare is a function object type (20.9). The return value of the function call operation applied to an object of type Compare, when contextually converted to bool (Clause 4), yields true if the first argument of the call is less than the second, and false otherwise. Compare comp is used throughout for algorithms
assuming an ordering relation.
Question:
Does ">" satisfy strict weak ordering? I expect so, but have no confidence.
Does greater operator “>” satisfy strict weak ordering?
The mathematical strict greater than relation is a strict weak ordering.
As for the operator in C++ langauge: For all integers types: Yes. In general: No, but in most cases yes. Same applies to strict less than operator.
As for the confusing quote, "is less than" in that context intends to convey that means that the the end result of the sort operation is a non-decreasing sequence i.e. objects are "less" or equal to objects after them. If std::greater is used as comparison object, then greater values are "lesser" in order.
This may be confusing, but is not intended to exclude strict greater than operator.
what is the case where > doesn't satisfy strict weak ordering?
Some examples:
Overloaded operators that don't satisfy the properties.
> operator on pointers that do not point to the same array has unspecified result.
> does not satisfy irreflexivity requirement for floating point types in IEEE-754 representation unless NaNs are excluded from the domain.
Even if the standard refers to "less than" for arbitrary Compare functions, that only implies "less than" in the context of the ordering.
If I define an ordering by comparison function [](int a, int b) { return a > b; }, then an element is "less than" another in this ordering if its integer value is greater. That's because the ordering I've created is an ordering of the integers in reverse order. You shouldn't read < as "less than" in orderings. You should read it as "comes before".
Whenever x < y is a strict weak ordering then x > y is also a strict weak ordering, just with the reverse order.
I don't know much about the math behind strict weak ordering. But I've read something:
An operator that satisfies strict weak ordering can express all other
logical operators
<(a, b) : (a < b)
<=(a, b): !(b < a)
==(a, b): !(a < b) && !(b < a)
!=(a, b) : (a < b) || (b < a)
>(a, b) : (b < a)
>=(a, b): !(a < b)
So does it means that there's no need for "==" definition, since "<" satisfies strict weak ordering, which can express all logical operators? (This may obviously seem not correct because I've seen classes define both < and ==.)
An easy to understand explanation would be also much-appreciated :D. Not necessary to be too "mathematical" or "technically right".
Could someone give me 1 or 2 (if they are easy to find) examples that the standard library defines other operators based on <? A reference to source code would be good enough.
First thing's first. Defining operator < doesn't mean you get a definition of operator == for free from the compiler. It still needs to be defined explicitly.
The table above assumes something that is true for many types and ordering relations, but not for all. It assumes that equivalence between two elements implies equality. That need not hold.
We can certainly use < to check for equivalence between two elements. They are equivalent according to the strict week ordering (that's what !(a < b) && !(b < a) means). It doesn't necessarily mean those elements are equal.
A good example would be case insensitive comparison between strings of characters. In that case we will certainly have !("ab" < "AB") && !("AB" < "ab"), and the two string are equivalent, but they aren't equal in value.
Having said all that. If the order relation you defined implies all the other ones for your type, there are tricks to generate all the other operations from it. Just as the table demonstrates.
So does it means that there's no need for "==" definition?
You still need to define it if you want the clients of your class to use it. It can be implemented in terms of the < operator. It might be easier to implement == operator in terms of the < operator. However, it might be better to implement it cleanly by itself for performance reasons.
From the perspective of Algebraic Structure, there's a kind of binary relation called "Partially Ordered Set". A partially ordered set is defined as a binary relation that is reflexive, antisymmetric and transitive.
In C++, one could implement bool operator<(a, b) as a POS relationship operator. In this case, !(a < b) && !(b < a) can hardly be considered equivalent to equality. One possible implementation is testing if a node is a descendant of another node. This is a perfect example of a POS relationship.
In C conditional-oriented operators evaluate to either 1 or 0 of type int (even if it does have dedicated _Bool type). Referring to C11 N1570 draft:
C11 §6.5.8/6 Relational operators
Each of the operators < (less than), > (greater than), <= (less than
or equal to), and >= (greater than or equal to) shall yield 1 if the
specified relation is true and 0 if it is false.107) The result has
type int.
C11 §6.5.9/3 Equality operators
The == (equal to) and != (not equal to) operators are analogous to the
relational operators except for their lower precedence.108) Each of
the operators yields 1 if the specified relation is true and 0 if it
is false. The result has type int. For any pair of operands, exactly
one of the relations is true.
C11 6.5.13/3 Logical AND operator
The && operator shall yield 1 if both of its operands compare unequal
to 0; otherwise, it yields 0. The result has type int.
C11 6.5.14/3 Logical OR operator
The || operator shall yield 1 if either of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
As I checked C++ seems to be different in this matter, as in following example (see http://ideone.com/u3NxfW):
#include <iostream>
#include <typeinfo>
int main() {
double x = 10.0;
std::cout << typeid(x <= 10.0).name() << std::endl;
return 0;
}
outputs b, which as I guess indicates bool type. Does C++ guarantee that all of these operators always evaluate to bool type (in contrast to C)?
No, because of operator overloading. This has been mentioned before, but I can give the real life example of expression templates. The idea, generally, is to allow writing "lazy" expressions (that is, really, function objects or ASTs) with syntax that is very similar to the normal, eager use of logical operators. Typically, many other operators, in particular arithmetic operators are also, overloaded.
For instance, one design goal of Boost.Lambda was to simplify the use of algorithms:
std::string str;
// ...
std:.string::iterator firstA = std::find_if(str.begin(), str.end(), _1 == 'a' || _1 == 'A');
Previously, in "pure" C++98, it was generally necessary to write numerous named functions or function objects before many standard algorithms could be used effectively.
Since C++11, Boost.Lambda is not as useful any more since lambda expressions have been added to the core language. There are still numerous EDSLs (embedded domain-specific languages) where C++11 lambdas cannot replace expression templates though, e.g. you may want to generate SQL command strings directly from a C++ EDSL in a way similar to LINQ in .NET, but as a portable library solution. Another example: the VexCL library uses expression templates to generate GPU kernels.
This is probably the only legitimate use of non-bool return types for overloaded logical operators, but it's not generally considered esoteric.
Contrary to C, in C++, relational operators, equality operators and logical operators (logical AND, logical OR and logical negation) all yield a value of type bool.
For example:
(C++11, 5.9p1 Relational operators) "[...] The type of the result is bool."
EDIT: for the sake of completeness, all the operators listed above can be overloaded and thus the resulting type can be changed. See Arne Vogel answer for real life example.
I asked me how the cmp function in std::sort and std::is_sorted is defined.
here are two documentations for is_sorted_until how say it should be operator< :
en.cppreference.com
cplusplus.com
But i think there should be a problem with equal elements.
The list {1,1,1} should not be sorted because 1<1==false.
But there is an example which says:
...
int *sorted_end = std::is_sorted_until(nums, nums + N);
...
1 1 4 9 5 3 : 4 initial sorted elements
but that should return 1 if < is used like documented.
It would work with <=, but that is not the way it is documented.
I'm really confused.
The comparison is required to define a strict weak ordering. A strict weak ordering defines a set of equivalence classes from the incomparability relation, i.e., if x < y is false, and y < x is false too (i.e. x and y cannot be compared with <), x and y are considered equivalent. These equivalence classes have a total order, and that's the total order resulting from the sort functions.
In the example given, {1,1,1} has only a single equivalence class, the one composed of {1,1,1}.
is_sorted_until finds the first element x[i] for which x[i] < x[i-1] is true.
To be exact, it's neither < nor <=, it is defaulted to std::less. That one in turn calls < for most types, except where it is specialized. For example, < for pointers does not generally give a strict ordering, while std::less does.
It does indeed use operator< unless you provide a custom comparison. But the definition of "sorted" is not a[n] < a[n+1] (which we might call "strictly sorted"), but !(a[n+1] < a[n]); so equal elements are considered sorted. This is equivalent to using <=, but (in common with all other standard algorithms) doesn't require that operator to be defined.
In general, all ordered comparisons must define a "strict weak ordering". "Strict" means that the comparison must be false for equivalent objects; so < is valid, while <= is not.
If you look at the example implementation, < is used for checking if the next element is less than the previous one:
if (*next < *first)
return next;
If it is, then the order is broken, and the function returns. I. e. the logic is reversed - the algorithm does not terminate if the next element is equal to the previous.
Can I use x on both sides of a boolean expression when I post-increment it on the left side?
The line in question is:
if(x-- > 0 && array[x]) { /* … use x … */ }
Is that defined through the standard? Will array[x] use the new value of x or the old one?
It depends.
If && is the usual short-circuiting logical operator, then it's fine because there's a sequence point. array[x] will use the new value.
If && is a user (or library) defined overloaded operator, then there is no short-circuit, and also no guarantee of a sequence point between the evaluation of x-- and the evaluation of array[x]. This looks unlikely given your code, but without context it is not possible to say for sure. I think it's possible, with careful definition of array, to arrange it that way.
This is why it's almost always a bad idea to overload operator&&.
By the way, if ((x > 0) && array[--x]) has a very similar effect (again, assuming no operator overloading shenanigans), and in my opinion is clearer. The difference is whether or not x gets decremented past 0, which you may or may not be relying on.
Yes, it is well defined. && introduces a sequence point.