可変引数は「危険」なので、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()」は、一文字を書き戻す。