« なんとなくリフレクション in C++ | メイン | Pathtraq の API を公開しました »

2008年06月27日

C++ で自動型変換

 C++ の拡張ライブラリである boost には、lexical_cast というライブラリがあって、iostream への入出力ができる型ならなんでも文字列化 (その逆も) できるので、とても便利です。でも、lexical_cast は、int → long のような変換の場合にも iostream を使った変換をしてしまうので、汎用のリフレクションコードを書こうとすると、そのままでは使いにくいです (オーバーヘッドが大きすぎる)。というわけで、変換前後の型に応じて、static_cast と lexical_cast を自動的に切り替えるようなキャスト関数を作ってみました。こんな感じで使います。

// calls lexical_cast<int>(123)
int i = intelligent_cast<int>("123");

// calls static_cast<long>(123)
long l = intelligent_cast<int>(123);

// calls std::string(const char*)
std::string s = intelligent_cast<std::string>("abc");

 これで、不用意に数値型間や std::string → std::string のような変換 (コピー) が必要になる場合でも、速度の低下を心配する必要がなくなりました。

 ライブラリのコードは以下のような感じ。boost におんぶにだっこなので簡単です (std::string については、実用上の観点から専用コードを追加しています) 。最新版は CodeRepos (/lang/cplusplus/reflection) においてあるので、バグ等ありましたら、指摘もしくは修正いただければ幸いです。

namespace intelligent_cast_ns {
  
  template <typename Target, typename Source, bool IsConvertible>
  struct cast_op {
    Target operator()(const Source &s) const {
      return boost::lexical_cast<Target>(s);
    }
  };
  
  template <typename Target, typename Source>
  struct cast_op<Target, Source, true> {
    Target operator()(const Source &s) const {
      return static_cast<Target>(s);
    }
  };
  
  template <typename T>
  struct cast_op<std::basic_string<T>, const T*, false> {
    std::basic_string<T> operator()(const T* const &s) {
      return s;
    }
  };
  
  template <typename T, size_t N>
  struct cast_op<std::basic_string<T>, T [N], false> {
    std::basic_string<T> operator()(const T (&s)[N]) {
      return s;
    }
  };
  
};

template <typename Target, typename Source>
Target intelligent_cast(const Source &s)
{
  return intelligent_cast_ns::cast_op<Target, Source, boost::is_convertible<Target, Source>::value>()(s);
}

投稿者 kazuho : 2008年06月27日 17:22 このエントリーを含むはてなブックマーク このエントリーを含むはてなブックマーク

トラックバック

このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1947