2014-01-22

C++03とC++11の違い:数値ライブラリー編

C++03とC++11の違いシリーズもそろそろ終わりが近づいていきた。今回は数値ライブラリー編だ。といっても、中身はひとつ、std::complexについてだ。

変更:std::complex<T>の特殊化の表現方法が規定された

C++03では、std::complexのメモリレイアウト、すわなち、オブジェクトがストレージ上でどのように表現されているかは、規定されていなかった。C++11では、C99の複素数ライブラリーと整合性をとるために、C++における複素数ライブラリーであるstd::complexの表現方法を厳格に規定した。

これにより、実装依存のメモリレイアウトに依存しているC++03のコードは、C++11では動かなくなるおそれがある。もっとも、そのようなコードは、もともと規格が動作を保証しないコードなので、自業自得だとも言える。

さて、std::complex<:T>:の表現方法はどのように規定されたのか。それは§26.4に書いてある。簡単にまとめると以下のようになる。

今、zがlvalue式で、その型がcv std::complex<T>であり、Tがfloat, double, long doubleのいずれかであるとすると、

  • 式、reinterpret_cast<cv T(&)[2]>(z)は、正しく動く
  • 式、reinterpret_cast<cv T(&)[2]>(z)[0]は、zの実数部を意味する
  • 式、reinterpret_cast<cv T(&)[2]>(z)[1]は、zの虚数部を意味する

さらに今、cv std::complex<T> *型の式aがあったとして、a[i]は、妥当であるとすると、

  • reinterpret_cast<cv T*>(a)[2*i]は、a[i]の実数部を意味する
  • reinterpret_cast<cv T*>(a)[2*i + 1]は、a[i]の虚数部を意味する

まあ、かなりCの構造体(構造体のアドレスは実数部のアドレスと等しく、実数部と虚数部の間にパディングなし)に近いようなレイアウトになるわけだ。もちろん、C言語でもこの手の詳細は未規定なのだが。

あるいは、コードで書いたほうがわかりやすいかもしれない。もちろん、このような規定を正確に記述できる機能は標準C++にはないが、例えば以下のようなコードが、よくある環境では上のような意味になるかもしれない。

// 実装依存の例示用コード
template < typename T >
struct complex ;

template < >
struct complex<float>
{
    float real ;
    float imarginary ;
} ;

このような表現の詳細に頼ったコードは書きたくないものだが・・・、必要になるのかも知れぬ。

No comments: