とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

uint16_t から推論して uint_fast16_t を得る

C++0x 〜auto に対する不満 - Diary of Chiharu - Chiharu の日記

私、上記のケースで std::uint_fast16_t をさっと導き出せる自信がありません。下記のように書けたら最高なんですけれど、そういう機能は C++0x にはないのかな。

auto_fast aVal = iImage.getWidth(); // auto_fast = std::uint_fast16_t

autoだけで,似たようなことはできると思います。
ここではオーバーロードを使って実現してみました。

// こういうのを準備する
#include<cstdint>
inline int_fast8_t fast_cast(int8_t n){return static_cast<int_fast8_t>(n);}
inline int_fast16_t fast_cast(int16_t n){return static_cast<int_fast16_t>(n);}
inline int_fast32_t fast_cast(int32_t n){return static_cast<int_fast32_t>(n);}
inline int_fast64_t fast_cast(int64_t n){return static_cast<int_fast64_t>(n);}
inline uint_fast8_t fast_cast(uint8_t n){return static_cast<uint_fast8_t>(n);}
inline uint_fast16_t fast_cast(uint16_t n){return static_cast<uint_fast16_t>(n);}
inline uint_fast32_t fast_cast(uint32_t n){return static_cast<uint_fast32_t>(n);}
inline uint_fast64_t fast_cast(uint64_t n){return static_cast<uint_fast64_t>(n);}


struct Image {
 std::uint16_t getWidth() const {return 0;}
};

std::uint16_t foo(const Image& iImage)
{
 // ここで使う。aVal は uint_fast16_t 型になる。
 auto aVal = fast_cast(iImage.getWidth());
 // aVal に対していろいろ計算
 return aVal;
}

int main()
{
 foo(Image());
}

追記:問題点と解決策

boolやdoubleをfast_castすると,おそらく,int32_tにマッチしてしまい,間違っているint_fast32_tが返ってきます。想定外の型が渡されたなら,コンパイルエラーにするのが良いでしょう。
解決するにはオーバーロードの並びの次に

template<class T> void fast_cast(T) = delete;

を加えます。
これで,boolやdoubleを渡すと関数テンプレートにマッチし,その関数テンプレートはdeleteされているのでコンパイルエラーになります。
別解は,オーバーロードを使わずテンプレートの特殊化を使います。この別解についてはC++0x 〜auto のその後 - Diary of Chiharu - Chiharu の日記を参照のこと。