エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

ダークサイド

まずは自らのツイートの引用から。

operator , (コンマ演算子)のオーバーロードが…、わたしをC++のダークサイドへといざなう…。…ちょっとダークサイドをのぞいてきます…。

http://twitter.com/emattsan/status/9974443836

「見よダークサイド見よダークサイド 今キミ待つ闇からの/あのダークサイドあのダークサイドが 誘う闇の奥へ」http://bit.ly/aKGAks

http://twitter.com/emattsan/status/10170070411

というわけで。ダークサイドから帰還しました(=_=)ゝ:ビットをもっと自由自在に扱えるようにしてみた。 http://d.hatena.ne.jp/E_Mattsan/20100308/1268052182

http://twitter.com/emattsan/status/10170080405

よっふぃ〜さんがブログで言及して*1くださったように、このビット操作は実際の利用を考えた場合、使う人を惑わす危ういやり方なんですよね。


実のところ見た目の変態度だけでなく、予想外の振る舞いをしかねないので注意が必要です。

たとえばこんなコード。12ビットの数値のうち中央の4ビットをシフトしたい、という場合。

#include <iostream>

#include "Bits.h"

using namespace emattsan::bits;

int main(int, char* [])
{
    Signed<4> a, b, c;

    int n = 0x123;

    std::cout << std::hex;

    std::cout << "before:" << n << std::endl;

    (a, b, c) = n;

    std::cout << "a:b:c = " << a << ":" << b << ":" << c << std::endl;
    std::cout << "a:b << 2:c = " << a << ":" << (b << 2) << ":" << c << std::endl;

    n = (a, b << 2, c);

    std::cout << "after:" << n << std::endl;

    return 0;
}


これを実行すると、最初の3つの出力は次のようになります。

before:123
a:b:c = 1:2:3
a:b << 2:c = 1:8:3

なので、最後の出力は「183」と出てほしい気もしますが、現時点のコードでは実際はこうなります。

after:3


これは。Signedにはoperator <<が定義されていないので、オーバーロードされている型変換演算子によって組み込みの整数型に変換されてoperator <<が適用されます。
そうすると(a, b << 2, c)は、型で見ると(Signed<4>, long, Signed<4>)という式になります。operator , (Signed<4>, long)operator, (long, Signed<4>)という演算子は定義されていませんから、本来のoperator ,が機能します。結果、aの値が評価されて値は捨てられ、次にb << 2が評価されて値は捨てられ、最後にcが評価され値がnに代入されます。


これらを個人的には「C++のダークサイド」と呼んでいます。その力は強力なんですが、作り方使い方を間違えると収拾のつかないカオスな状況を生んでしまいます。


はてさて。当プログラムは、ダークサイドから力を持ち帰るのか、それとも混沌と化し闇に還るのか。自分の技術力の挑戦でもあります。