涼の成長記録

自らの人生に主導権を持つべく、独立を目指して2014年3月31日を持ってITエンジニアを退職。そんな23歳♂の成長記録。

条件演算子を使いこなせない

TDateTimeクラスとは?

さて、今日はタイトルの通り、条件演算子VCLのTDateTimeクラスの罠に引っかかりました。1時間ぐらい無駄にしたような気がします。今回起こった問題は、とあるTDateTime変数の"hh:nn:ss"情報が消えてしまうというもの。


まず、TDateTimeクラスについて。
System.TDateTime - XE2 API Documentation


つまり、こういうことです。

TDateTime クラスは、日付/時刻値を格納する double 型データ メンバ val を継承します。 TDateTime 値の整数部分は、1899年12月30日からの経過日数です。 TDateTime 値の少数部分は、時刻です。


先ほど書いた、"hh:nn:ss"情報(つまり時刻)が消えてしまうというのは、小数部分が消えてしまうということです。TDateTimeが整数部が日付で、小数部が時刻というのはあまり考えておりませんでした。IDE(C++Builder XE2)でデバッグ中に変数にマウスオーバーした時に表示される日時情報に、時刻が書いていないことに気付いたわけです。



悲劇の原因

で、結論から言うと、条件演算子が犯人でした。いや、この言い方は良くないですね。条件演算子の仕様を理解していない私が犯人でした。条件演算子には愛を持って接しています。何故かというと長くなるので、今日は止めておきますが、見やすくなるのであれば私は条件演算子推奨派です。
まあ、私みたいな底辺プログラマーが今回のような罠に引っかかるから、推奨されないのかもしれませんが。


勘の良い方はお気付きでしょうが、問題のコードはこんな感じです。

TDateTime __fastcall TSampleClass::getDateTime(unsigned int index) {
    return (index < m_Array.size()) ? m_Array.at(index).dateTime : 0;
}


引数で渡されたindexの範囲チェックをして、問題がなければTDateTime型の値を返して、もし範囲チェックが受からなければ0(1899/12/30 00:00:00)を返しているつもりで組んでおりました。しかし、条件演算子特性上、これでは駄目だったのです。



条件演算子とは?

条件演算子についてWikipedia大先生に聞いてみました。
条件演算子 - Wikipedia


今回は、この1文の仕様に甘えていたがために起こった悲劇です。

真式と偽式は同じ型の値を返さなければならない(暗黙に型変換可能なら許されることもある)


許されちゃったわけですよ。TDateTimeを期待しているm_Array.at(index).dateTimeはint型に暗黙に変換することが許されちゃったわけですよ。何故右に合わせるのかは、勉強不足である私には分かりません。右結合だから、というのは関係ありませんよね?底辺でごめんなさい。



解決

とりあえずの解決法としては、0をTDateTimeでキャストすることです。

TDateTime __fastcall TSampleClass::getDateTime(unsigned int index) {
    return (index < m_Array.size()) ? m_Array.at(index).dateTime : (TDateTime)0;
}


条件演算子なんて使わなければ、こんなことにはならなかったのですが。

TDateTime __fastcall TSampleClass::getDateTime(unsigned int index) {
    // 引数の値範囲チェック
    if (index >= m_Array.size()) {
        return 0;
    }

    return m_Array.at(index).dateTime;
}


いやー、無知は罪ですね。しかしやっぱり、プログラミングって面白いですね。
ではでは。