可変引数は「危険」なので、C++では「printf」を使わない文化がある。
それは、以前に説明した、しかしながら、printf のコンビニエンス性は捨てがたい、
そこで、boost::format に習って、組み込み向け utils::format クラスを提供した。
それでは、入力はどうしたものか・・・
一般的には、scanf を使って文字列中の数字を変換する。
しかし、scanf は C の API で、可変引数も使う、なので、format クラスに対応する
入力クラスも実装する必要性が大きい、そこで、input クラスを実装してみた。
※良くある、数字の変換に付き物の機能も追加した。
以下のように使う。
int a; uint32_t b; int n = (utils::input("%d[, ]%x", "-99 100") % a % b).num(); std::cout << a << ", " << b << std::endl; std::cout << "N: " << n << std::endl;
結果:
-99, 256 N: 2
上のサンプルでは、「%d」、「%x」の仕切りとして、「,」又は「 」(スペース)を
使う事ができる。
これは、正規表現に似た書式を簡略化したものだが、機能的には最低限の物しか無い。
※豊富な機能を盛り込むとコードが肥大化するし、たぶん実際には、それ程高機能で
無くても困らないと思えるからだ。
また、取り込んだ数は、「num()」を使って取得する事ができる。
input クラスの書式は以下のようになっている。
//-----------------------------------------------------------------// /*! @brief コンストラクター @param[in] form 入力形式 @param[in] inp 変換文字列(nullptrの場合、sci_getch で取得) */ //-----------------------------------------------------------------// basic_input(const char* form, const char* inp = nullptr);
basic_input クラス・テンプレートは、以下のように typedef されている。
typedef basic_input<def_chainp> input
ここで、「def_chainp」クラスは以下のようになっている。
自前の特殊クラスを作って食わせる事ができる。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// /*! @brief 標準入力ファンクタ */ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// class def_chainp { const char* str_; char last_; bool unget_; public: def_chainp(const char* str = nullptr) : str_(str), last_(0), unget_(false) { } void unget() { unget_ = true; } char operator() () { if(unget_) { unget_ = false; } else { if(str_ == nullptr) { last_ = sci_getch(); } else { last_ = *str_; if(last_ != 0) { ++str_; } } } return last_; } };
※「unget()」は、一文字を書き戻す。