Seaside Laboratory

Post

C++ の条件演算子 (三項演算子) と型変換

独自に作成した型を条件演算子に使ったら想定と違う挙動になってしまい、原因を突き止めるまでに時間がかかってしまった。

条件演算子に使った独自の型を簡単に書くと以下のようになる。

class mydouble
{
    double m_value;

public:
    mydouble( int n ) : m_value( n )
    {
        puts( "mydouble( int n )" );
    }

    mydouble( double f ) : m_value( f )
    {
        puts( "mydouble( double f )" );
    }

    operator int ()
    {
        puts( "operator int ()" );
        return this->m_value;
    }

    operator double ()
    {
        puts( "operator double ()" );
        return this->m_value;
    }
};

int と double による初期化と値の取り出しができる浮動小数点数を表す型。どの関数が呼ばれたか分かるようにデバッグ文が挿入してある。まずは試しに簡単な代入をして結果を確認。

// プログラム
mydouble d1 = 12;
mydouble d2 = 3.4;

// 出力
mydouble( int n )
mydouble( double f )

型に応じたコンストラクタが呼び出されていて特に問題はない。今度はこの型を条件演算子に組み入れて使ってみる。

// プログラム
mydouble d1 = 1.2;
mydouble d2 = true ? d1 : 34;

// 出力
mydouble( double f )
operator int ()
mydouble( int n )

後半の二行が条件演算子による出力になるが、式の結果が int として解釈されてしまったので、d1 の operator int が呼び出され、その値を代入するために d2 の int 版コンストラクタが呼び出されている。

mydouble は浮動小数を表す型なので無意識のうちに、

mydouble d2 = true ? 1.2 : 34;

と脳内展開されていたが、実際は

mydouble d2 = true ? 1 : 34;

と解釈され、小数部が切り捨てられた値が代入されてしまう。

ちゃんと C++ の仕様を確認してみようということで、「プログラミング言語 C++」の算術変換の項を見てみると、以下の様に書いてある。

mydouble はこれらの条件にほぼ当てはまらず、最後の整数の格上げが適用されている模様。クラスがどの型になるのか判別できていないことが原因なので、組み込み型だけを使って書くと違った結果になる。

// プログラム
double d1 = 1.2;
double d2 = true ? d1 : 34;
printf( "%f\n", d2 );

// 出力
1.200000

条件演算子を使うときは同じ型に統一するのがよさそうです。