私は常に、比較ステートメント、つまりX == Y
またはX != Y
がフォーマットであり、ステートメントを&&
またはでチェーンするという印象を受けてきました||
。
X == (Y || Z)
代わりに書く方法はありませんかX == Y || X == Z
?
編集:これをきれいに行うことは不可能であることが確立されているので、他にどのようにそれを行うことができますか?
私は常に、比較ステートメント、つまりX == Y
またはX != Y
がフォーマットであり、ステートメントを&&
またはでチェーンするという印象を受けてきました||
。
X == (Y || Z)
代わりに書く方法はありませんかX == Y || X == Z
?
編集:これをきれいに行うことは不可能であることが確立されているので、他にどのようにそれを行うことができますか?
#include <algorithm>
#include <array>
#include <string>
#include <iostream>
#include <initializer_list>
template<class Type, class Next>
bool is_one_of(const Type& needle, const Next& next)
{return needle==next;}
template<class Type, class Next, class ... Rest>
bool is_one_of(const Type& needle, const Next& next, Rest... haystack)
{return needle==next || is_one_of(needle, haystack...);}
int main() {
std::string X, Y;
if (is_one_of(X, Y, "HI"))
std::cout << "it is!";
else
std::cout << "it isn't!";
return 0;
}
コンパイルの証明。 Xeoはまた、実際のニーズや要望に応じて、それを観察し、有用であった可能性がありますstd::any_of
。 std::all_of
std::none_of
C++で要求したことを実行するためのクリーンな方法はありません。
多くの人をつまずかせるのは、それX == (Y || Z)
は合法的な表現であり、コンパイラーは文句を言わないということです。ただのバグになります。各C++ステートメントは、それ自体でtrue / falseと評価される必要があり、演算子はそれらをつなぎ合わせるだけです。あなたが提案していることは、いくつかの本質的なリスト構造を必要とするでしょう。多くの言語(Pythonなど)にはそれがありますが、C++にはありません。
演算子のオーバーロードを使用すると、必要な構文を正確に取得できる場合があります。しかし、アダムが指摘するように、それは有効な表現を除外することにつながる可能性があります。
以下は、演算子のオーバーロード、テンプレート関数、およびMooing Duckのより優れたソリューションと同様の構文を実現するためのマクロを備えたテンプレートですが、C ++ 11を必要とせず、||
演算子を使用して「干し草の山」コレクションを示すことができます。
template <typename T>
struct MultiOrComparable {
mutable std::set<T> vals;
const MultiOrComparable & operator || (T v) const {
vals.insert(v); return *this;
}
bool operator == (T v) const { return vals.find(v) != vals.end(); }
};
template <typename T>
MultiOrComparable<T> MultiOrComparableStart (T) {
return MultiOrComparable<T>();
}
#define IsOneOf(x, y) ((MultiOrComparableStart(x)||y) == x)
次に、次のプログラムが「機能」します。
enum Foo { A, B, C, D };
int
main ()
{
if (!IsOneOf(A, B || C || D)) {
std::cout << "!=" << std::endl;
}
if (IsOneOf('a', 'x' || 'y' || 'z' || 'a')) {
std::cout << "==" << std::endl;
}
}
式テンプレートを使用して目的を達成する方法があるかもしれません。これにアプローチする方法のスケッチの下(コンパイルされない、多くの詳細が欠落している、警告レクター)。最初に、論理値を表すクラステンプレートを設定し、それらに対していくつかの演算子を定義します。
template<typename T, typename Type = Atomic<T> >
class Logical;
template<typename T, typename E1, typename E2>
Logical<T, OpOr<T, E1, E2> > operator||(Logical<T, E1> lhs, Logical<T, E2> rhs);
template<typename T, typename E1, typename E2>
Logical<T, OpAnd<T, E1, E2> > operator&&(Logical<T, E1> lhs, Logical<T, E2> rhs);
template<typename T, typename E1, typename E2>
Logical<T, OpEq<T, E1, E2> > operator==(Logical<T, E1> lhs, Logical<T, E2> rhs)
{ return OpEq<T, E1, E2>()(lhs, rhs); } // delegate to class template
関数テンプレートは部分的に特殊化できないため、実際の作業をクラステンプレートに委任します。
// primary template
template<typename T, typename E1, typename E2> class OpEq;
// specialization for atomic comparisons
template<typename T>
class OpEq<T, Atomic<T>, Atomic<T> >
{
bool operator()(Atomic<T> lhs, Atomic<T> rhs)
{ return lhs == rhs; }
}
// apply distributive rule
template<typename T>
class OpEq<T, Atomic<T>, OpOr<T, Atomic<T>, Atomic<T> > >
{
bool operator()(Atomic<T> lhs, OpOr<T, Atomic<T>, Atomic<T> > rhs)
{ return (lhs == rhs.first()) && (lhs == rhs.second()); }
}
明らかに、必要なものに自然なC++構文を取得するために必要な多くの重いテンプレート機構があります。しかし、多くの努力と読み上げで、あなたは最終的に何か良いものを手に入れるかもしれません。(Atomic、OpAnd、OpOr、部分式の1番目と2番目のブランチを保持するセットアップ表現などを定義する必要があります)
ただし、成功したとしても、スキームに非常に奇妙なセマンティクスが含まれることになります。あなたが提案しているのは、左に分配する必要==
があります-または。つまり、解析します||
&&
X == (Y @OP Z)
なので
(X == Y) @OP (X == Z)
またはに@OP
等しい。対称性を維持することを要求するのは当然だと思います。これには、overとの右分配法則も課す必要があります。つまり、解析します&&
||
==
==
&&
||
(X @OP Y) == Z
なので
(X == Z) @OP (Y == Z)
ただし、この2つを式asとして組み合わせると、(A @OP1 B) == (C @OP2 D)
論理的な不整合が発生します。たとえば、結果は、左分布と右分布を適用する順序によって異なります。
左から右へ:
(A @OP1 B) == (C @OP2 D)
((A @OP1 B) == C) @OP2 ((A @OP1 B) == D)
((A == C) @OP1 (B ==C)) @OP2 ((A == D) @OP1 (B == D))
右から左:
(A @OP1 B) == (C @OP2 D)
(A == (C @OP2 D)) @OP1 (B == (C @OP2 D))
((A == C) @OP2 (A == D)) @OP1 ((B == C) @OP2 (B == D))
どちらの場合も、同じ4組の要素が比較されていますが、それらが式ツリーに伝播される方法は微妙に異なります。@OP1
とが同じである場合@OP2
は、ツリー全体をフラット化し、用語を並べ替えて、一意の結果を得ることができます。、の両側で同じ演算子を使用すると、とは結合法則であると同時に可換==
であるため、問題なく機能します。&&
||
ただし、混合演算子の場合、結果の式は一般に異なります。
更新:この回答や他の回答へのコメントで述べたように、組み込み型の特定のプロパティも失われます。まず、オーバーロードされた演算子が従わない短絡規則。ポインタの逆参照やその他のリソースアクセス(if(p && p->value())
またはif(file && file.open())
など)を含まない論理式の場合、これは正確性には影響せず、効率にのみ影響します。それ以外の場合は注意してください!第二に、定数/式の混合評価がうまくいかないことも言及されました。これには単純な(しかし冗長な)修正があります。ラッパーとしてstd::integral_constant
(または)を使用するだけです。boost::mpl::int_