だからこれはもっと理論的な問題です。 C++およびそれを直接ベースにした言語(in、Java、C#、PHP)では、 ショートカット演算子 のように、ほとんどの二項演算子の結果を第1オペランドに割り当てることができます
a += 3; // for a = a + 3
a *= 3; // for a = a * 3;
a <<= 3; // for a = a << 3;
しかし、私がブール式をトグルしたいとき、私はいつも自分自身のようなものを書いているのに気づきます。
a = !a;
a
がのような長い式であるとき、これはいらいらします。
this.dataSource.trackedObject.currentValue.booleanFlag =
!this.dataSource.trackedObject.currentValue.booleanFlag;
(ええ、デメテルの法則、私は知っています)。
だから、私は思っていた、 単項ブール型のトグル演算子 を使って、a
の式を繰り返さなくてもa = !a
を省略できるようにする言語はありますか。
!=a;
// or
a!!;
私たちの言語が(C++のbool
のように)適切なブール型を持ち、a
がその型であると仮定しましょう(だからCスタイルのint a = TRUE
はありません)。
あなたが文書化された情報源を見つけることができるならば、私はまたどうか学ぶことに興味があるでしょう。 bool
が組み込み型になったときにC++設計者はそのような演算子を追加することを検討しました。
(注:代入では=
を使用すべきではなく、++
と+=
は有用な演算子ではなく設計上の欠陥ではないとの意見があります。 ).
...これにより、
a
の式を繰り返すことなく、a = !a
を短縮できます ...
このアプローチは、実際には純粋な「変更フリップ」演算子ではありませんが、上記の基準を満たします。式の右側には変数自体は含まれません。
ブール値のXOR割り当て(たとえば、^=
)がある言語では、a
へのXOR割り当てにより、変数の現在の値、たとえばtrue
を反転できます。
// type of a is bool
a ^= true; // if a was false, it is now true,
// if a was true, it is now false
以下のコメントで@cmasterが指摘したように、上記ではa
がbool
型であり、たとえば整数またはポインター。 a
が実際には別のもの(たとえば、それぞれ0b1
または0b0
ではないビット表現で「真」または「偽」の値に評価される非bool
のもの)の場合、上記は成り立ちません。
具体例として、Javaは、これが明確に定義されており、サイレント変換の対象ではない言語です。以下から@Boannのコメントを引用:
Javaでは、
^
および^=
がブール値および整数の動作を明示的に定義しています( 15.22.2。ブール論理演算子&
、^
、および|
)。両側は整数でなければなりません。これらの型の間でサイレント変換はありません。そのため、a
が整数として宣言されている場合、静かに誤動作することはありませんが、むしろコンパイルエラーが発生します。したがって、a ^= true;
は安全で、Javaで明確に定義されています。
toggle()
Swift 4.2の時点で、次の進化の提案が受け入れられ、実装されました。
これにより、ネイティブの toggle()
関数がSwiftの Bool
タイプに追加されます。
toggle()
ブール変数の値を切り替えます。
宣言
mutating func toggle()
議論
このメソッドを使用して、ブール値を
true
からfalse
に、またはfalse
からtrue
に切り替えます。var bools = [true, false] bools[0].toggle() // bools == [false, false]
これは、それ自体は演算子ではありませんが、ブール値の切り替えのための言語固有のアプローチを許可します。
C++では、演算子の意味を再定義するという枢機卿の罪を犯すことが可能です。これを念頭に置いて、そして少しADLを踏まえて、私たちがユーザーベースで騒ぎを解き放つためにする必要があるのはこれだけです:
#include <iostream>
namespace notstd
{
// define a flag type
struct invert_flag { };
// make it available in all translation units at zero cost
static constexpr auto invert = invert_flag{};
// for any T, (T << invert) ~= (T = !T)
template<class T>
constexpr T& operator<<(T& x, invert_flag)
{
x = !x;
return x;
}
}
int main()
{
// unleash Hell
using notstd::invert;
int a = 6;
std::cout << a << std::endl;
// let confusion reign amongst our hapless maintainers
a << invert;
std::cout << a << std::endl;
a << invert;
std::cout << a << std::endl;
auto b = false;
std::cout << b << std::endl;
b << invert;
std::cout << b << std::endl;
}
予想される出力:
6
0
1
0
1
アセンブリ言語を含める限り...
ビット単位の補数の場合はINVERT
。
論理的な(true/false)補完のための0=
。
アセンブリ言語
NOT eax
https://www.tutorialspoint.com/Assembly_programming/Assembly_logical_instructions.htm を参照してください。
C99のbool
をデクリメントすると、いくつかの小さなマイクロコントローラの方言でサポートされているbit
タイプをインクリメントまたはデクリメントするので、望ましい効果があります(これは、ビットをシングルビット幅のビットフィールドとして扱うためですそしてすべての奇数は1になります。 bool
型セマンティクスの大ファンではないので、そのような使用法は特にお勧めしません。[IMHO、0または1以外の値が格納されているbool
は読み取り時に動作するように型を指定するべきです。あたかも不特定の(必ずしも一貫していない)整数値を保持するかのように。プログラムが0や1であることが知られていない整数値を格納しようとしているなら、最初にそれに!!
を使うべきです]。
私はあなたがこれだけに基づいて言語を選ぶつもりではないと思います:-)いずれにせよ、あなたはC++でこれのようなことをすることができます:
inline void makenot(bool &b) { b = !b; }
例えば、以下の完全なプログラムを見てください。
#include <iostream>
inline void makenot(bool &b) { b = !b; }
inline void outBool(bool b) { std::cout << (b ? "true" : "false") << '\n'; }
int main() {
bool this_dataSource_trackedObject_currentValue_booleanFlag = false;
outBool(this_dataSource_trackedObject_currentValue_booleanFlag);
makenot(this_dataSource_trackedObject_currentValue_booleanFlag);
outBool(this_dataSource_trackedObject_currentValue_booleanFlag);
makenot(this_dataSource_trackedObject_currentValue_booleanFlag);
outBool(this_dataSource_trackedObject_currentValue_booleanFlag);
}
これは、予想どおりに出力されます。
false
true
false
PostScript は、 連結 / スタック指向 Forthのような言語であり、単項トグル、notを持ちます。 not演算子は、スタックの先頭にある値を切り替えます。例えば、
true % Push true onto the stack
not % invert the top of stack
% the top of stack is now false
PostScriptランゲージリファレンスマニュアル(pdf) 、pを参照してください。 458。
Visual Basic.Netはこれを拡張メソッドでサポートしています。
拡張方法を次のように定義します。
<Extension>
Public Sub Flip(ByRef someBool As Boolean)
someBool = Not someBool
End Sub
そしてそれを次のように呼びます。
Dim someVariable As Boolean
someVariable = True
someVariable.Flip
したがって、元の例は次のようになります。
me.DataSource.TrackedObject.CurrentValue.BooleanFlag.Flip
この問題は、純粋に理論的な観点からは本当に興味深いものです。 単項の、変化するブール値のトグル演算子が役に立つかどうか、あるいはなぜ多くの言語がそれを提供しないことを選んだのか、私はそれが実際に存在するかどうかを探るために探求しました。
TL; DR どうやらいいえ、しかしSwiftはそれを実装させます。それがどのように行われているのかを知りたいだけの場合は、この回答の一番下までスクロールできます。
さまざまな言語の機能を(すばやく)検索した後、この演算子を厳密に変化させるインプレース操作として実装した言語はないと言っても過言ではありません(見つけた場合は修正してください)。それで、次はあなたがそれを構築することを可能にする言語があるかどうか見ることでしょう。これに必要なことは2つのことです。
多くの言語は、これらの要件のどちらかまたは両方をサポートしていないためにすぐに除外されます。 Java の1つでは、演算子のオーバーロード(またはカスタム演算子)は許可されていません。さらに、すべてのプリミティブ型は値渡しされます。 Go は演算子オーバーロードをサポートしていません( hacks を除く)。 Rust は、カスタム型に対してのみ演算子のオーバーロードを許可します。あなたはほぼ Scala でこれを達成することができます。これは非常に独創的な名前の関数を使用し、括弧も省くことができますが、残念ながら参照渡しはありません。 Fortran カスタム演算子を許可しますが、特にinoutparameters)(通常の関数やサブルーチンで許可されている)を持つことを禁止しています。
ただし、必要なすべてのボックスにチェックマークを付ける言語が少なくとも1つあります。 Swift 。今後の.toggle()メンバー関数)にリンクしている人もいますが、inout引数をサポートする独自の演算子を書くこともできます。Loand behold:
prefix operator ^
prefix func ^ (b: inout Bool) {
b = !b
}
var foo = true
print(foo)
// true
^foo
print(foo)
// false
Rustでは、Not
特性を実装する型を拡張するためにあなた自身の特性を作成することができます。
use std::ops::Not;
use std::mem::replace;
trait Flip {
fn flip(&mut self);
}
impl<T> Flip for T
where
T: Not<Output = T> + Default,
{
fn flip(&mut self) {
*self = replace(self, Default::default()).not();
}
}
#[test]
fn it_works() {
let mut b = true;
b.flip();
assert_eq!(b, false);
}
^= true
を推奨どおりに使用することもできます。Rustの場合は、CやC++のようにfalse
が「偽装された」整数ではないため、これを行うことは考えられません。
fn main() {
let mut b = true;
b ^= true;
assert_eq!(b, false);
let mut b = false;
b ^= true;
assert_eq!(b, true);
}
変数が bool型 (TrueまたはFalse)で exclusive or (^=)
演算子を持つ場合、Pythonはそのような機能をサポートします。
a = False
a ^= True
print(a) # --> True
a ^= True
print(a) # --> False