I've always been under the impression that for any comparison statement, i.e. X == Y
or X != Y
is the format, and you chain statements together with &&
or ||
.
Is there not some way to write X == (Y || Z)
instead of X == Y || X == Z
?
Edit: Since it has been established that this is not possible to do cleanly, how else could it be done?
There's no clean way to do what you ask in C++.
What trips many people up is that
X == (Y || Z)
may be a legal expression and the compiler will not complain. It will just be a bug. Each C++ statement must evaluate to true/false on its own and the operators just string them together. What you're suggesting would require some intrinsic list structure. Many languages have that (like Python), but C++ does not.With operator overloading, you might be able to get the exact syntax that you want. But, as Adam points out, that could lead to excluding valid expressions.
Below is a template with operator overloading, a template function, and a macro to achieve a syntax similar to Mooing Duck's nicer solution, but without requiring C++11, and allowing the use of the
||
operator to denote the "haystack" collection.Then, the following program "works":
proof of compilation. Xeo also observes that
std::any_of
,std::all_of
andstd::none_of
may have been useful, depending on your actual needs and desires.There might be a way to achieve what you want with expression templates. Below a sketch of how to approach this (does not compile, lots of details missing, caveat lector). First you setup a class template to represent logical values and define some operators over them.
Because function templates can't be partially specialized, you delegate your actual work to class templates.
Obviously, there is a lot of heavy template machinery involved to get natural C++ syntax for what you want. But with a lot of effort and reading up you might eventually get something nice. (You'd have to define Atomic, OpAnd, OpOr, setup representations holding the first and second branches of subexpression etc. etc.)
However, even if you would succeed, you would get really weird semantics in your scheme. What you are proposing is require
==
to be left-distributive over||
or&&
. I.e. to parseas
with
@OP
equal to&&
or||
. I think it would be natural to require that==
remains symmetric. This would require you also to impose right-distributivity of==
over&&
and||
. I.e. to parseas
However, if you combine the two with expression as
(A @OP1 B) == (C @OP2 D)
, you get logical inconsistencies. E.g. the result is depending on the order in which you apply left-distribution and right-distribution.Left-then-right:
Right-then-left:
In both cases, the same 4 pairs of elements are being compared, but the way they are being propagated up the expression tree is subtly different. If
@OP1
and@OP2
are the same, then you can flatten the entire tree and re-order the terms to get a unique result. , it works out OK if you use the same operators on both sides of the==
, because both&&
and||
are associative as well as commutative.But for mixed operators the resulting expressions will in general be different.
UPDATE: as mentioned in the comments to this and other answers, you also loose certain properties of built-in types. First, the short-circuit rules, which are not obeyed by overloaded operators. For logical expressions not involving pointer dereferencing or other resource access (
if(p && p->value())
orif(file && file.open())
etc.) this would not influence correctness but only efficiency. Otherwise be careful! Second, it was also mentioned that mixed evaluations of constants/expressions would go wrong. This has a simple (but verbose) fix: simply usestd::integral_constant
(orboost::mpl::int_
) as a wrapper.