WisdomSoft - for your serial experiences.

2.9 結合法則

複数の項からなる演算において、どちらの項から順番に評価されるのかは演算子によって決まりがあります。これを結合法則と呼びます。

2.9.1 式の実行順序

プログラムの内容によっては、演算子に与えられる項の左右どちらが優先して実行されるのかが重要になることがあります。例えば x + y + z という式があったとき、先に計算されるのは x + y でしょうか。それとも y + z でしょうか。加算演算であれば、どちらの順でも結果は同じですが、x / y / z という式であれば計算順序が (x / y) / z と x / (y / z) では結果が異なってしまいます。

x + y + z のように、同じ優先順位の演算子が左から右に向かって計算されるのか、または右から左に向かって計算されるのか、という決まりを結合規則(associativity)と呼びます。このとき、左から右に向けって結合する演算を左結合、右から左に向かって結合する演算を右結合と呼びます。

例えば、算術演算子は左から右に向かって計算される左結合です。当然 x + y + z は x + y が先に計算されます。よって、コードとして書かれた算術式でも、数学で見られる式と同じ順序で計算されます。

一方で、右から左に向かって結合される演算子も存在します。代表的な右結合は代入演算子です。代入演算子は右項から計算されるため x = y + z という式は y + z が計算されてから x に結果が代入されることになります。

代入演算子が右結合であることを調べるには、代入演算子の結果を別の変数に代入すると確認できます。代入演算子は右項を変数に保存するだけではなく、その演算結果を返しています。代入演算子の結果は代入後の左項の変数自身です。

コード1
#include <iostream>

int main()
{
	int x, y, z;
	x = y = z = 10;

	std::cout << "x=" << x << "\n";
	std::cout << "y=" << y << "\n";
	std::cout << "z=" << z << "\n";

	return 0;
}
実行結果
コード1 実行結果

コード1は代入演算子を連続させて 10 という値を x 変数、y 変数、z 変数それぞれに代入しています。x = y = z = 10 という演算では、代入演算子が右結合なので右項が優先して評価されます。つまり x = (y = (z = 10)) と同義です。z = 10 の結果は 10 を代入した後の z そのものです。よって y = z では 10 を代入した後の z の値が y に代入されるため y にも 10 が代入されるという仕組みです。

代入演算子の結果は左辺値です。x = 10 という代入演算の結果は x に 10 を代入した後の x 変数そのものであると解釈できます。従って、代入演算子の結果を別の代入演算子の左項に置くこともできます。例えば (x = 10) = 20 という演算も問題ありません。

コード2
#include <iostream>

int main()
{
	int x, y, z;
	(x = y = 0) = z = 10;

	std::cout << "x=" << x << "\n";
	std::cout << "y=" << y << "\n";
	std::cout << "z=" << z << "\n";
	return 0;
}
実行結果
コード2 実行結果

コード2は、代入演算子の左項に別の代入演算子の結果を指定しています。x 変数、y 変数、z 変数への代入演算の順番を明示的に括弧を使うと (x = (y = 0)) = (z = 10) となります。最初に y 変数に 0 が代入され、この結果が x 変数にも代入されます。よって、演算の過程で一度 x 変数には 0 が格納されることになります。優先順位の高い ( ) 内の演算が終わった後、続いて z = 10 が評価され z 変数に 10 が格納されます。最後に右項である z 変数の値が、左項に代入されます。この結果から (x = y = 0) という演算の結果が x 変数を指す左辺値であることが確認できます。