web-dev-qa-db-ja.com

任意の言語に単項ボール型トグル演算子がありますか?

だからこれはもっと理論的な問題です。 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++設計者はそのような演算子を追加することを検討しました。


(注:代入では=を使用すべきではなく、+++=は有用な演算子ではなく設計上の欠陥ではないとの意見があります。 ).

139
CompuChip

ブールビットの切り替え

...これにより、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が指摘したように、上記ではabool型であり、たとえば整数またはポインター。 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]

これは、それ自体は演算子ではありませんが、ブール値の切り替えのための言語固有のアプローチを許可します。

143
dfri

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
42
Richard Hodges

アセンブリ言語を含める限り...

FORTH

ビット単位の補数の場合はINVERT

論理的な(true/false)補完のための0=

37
Dr Sheldon

アセンブリ言語

NOT eax

https://www.tutorialspoint.com/Assembly_programming/Assembly_logical_instructions.htm を参照してください。

31

C99のboolをデクリメントすると、いくつかの小さなマイクロコントローラの方言でサポートされているbitタイプをインクリメントまたはデクリメントするので、望ましい効果があります(これは、ビットをシングルビット幅のビットフィールドとして扱うためですそしてすべての奇数は1になります。 bool型セマンティクスの大ファンではないので、そのような使用法は特にお勧めしません。[IMHO、0または1以外の値が格納されているboolは読み取り時に動作するように型を指定するべきです。あたかも不特定の(必ずしも一貫していない)整数値を保持するかのように。プログラムが0や1であることが知られていない整数値を格納しようとしているなら、最初にそれに!!を使うべきです]。

30
supercat

私はあなたがこれだけに基づいて言語を選ぶつもりではないと思います:-)いずれにせよ、あなたは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
28
paxdiablo

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。

22
Wayne Conrad

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
21
Reginald Blue

この問題は、純粋に理論的な観点からは本当に興味深いものです。 単項の、変化するブール値のトグル演算子が役に立つかどうか、あるいはなぜ多くの言語がそれを提供しないことを選んだのか、私はそれが実際に存在するかどうかを探るために探求しました。

TL; DR どうやらいいえ、しかしSwiftはそれを実装させます。それがどのように行われているのかを知りたいだけの場合は、この回答の一番下までスクロールできます。


さまざまな言語の機能を(すばやく)検索した後、この演算子を厳密に変化させるインプレース操作として実装した言語はないと言っても過言ではありません(見つけた場合は修正してください)。それで、次はあなたがそれを構築することを可能にする言語があるかどうか見ることでしょう。これに必要なことは2つのことです。

  1. 関数を使って(単項)演算子を実装できること
  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
14
Lauri Piispanen

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);
}
13

Pythonの場合

変数が bool型 (TrueまたはFalse)で exclusive or (^=) 演算子を持つ場合、Pythonはそのような機能をサポートします。

a = False
a ^= True
print(a)  # --> True
a ^= True
print(a)  # --> False
5
Andriy Ivaneyko

C#の場合

boolean.variable.down.here ^= true;

ブール値の^演算子はXORであり、trueのXORは反転と同じです。

2
rakensi