いろいろPCのトラブルとか暇無いとか忘れてたとかで、やっと記事第1号を書く事になった。いや忘れてたは無いだろ忘れてたは、とか言うツッコミを期待恐れながら、記念すべき第1号記事を書いてみたいと思う。
閑話休題。
さて、第1号記事の内容はこのblog作った当初から決めていて、『BASICのMID$()をC++で再現する』というものだ。ネタ元はcppllの投稿『[cppll:11798] BASIC の MID$』。
一部のBASIC実装に在ったMID$()という関数をC++で実装するには?というもの。この関数、ただの関数ではなく代入の左辺に使うことも出来る。
10 STR$ = "hogehoge"
20 RES$ = MID$(STR$, 3, 4) ' STR$の(1バイト文字単位で)3文字目から4文字取得
30 PRINT RES$
40 MID$(STR$, 3, 4) = "PIYO" ' STR$の3文字目から4文字をPIYOに変える
50 PRINT STR$
gehohoPIYOge
20行のようなものは普通に書ける(というか普通の関数はこういう仕様)が、40のようなものを書けるようにする為には……?
早速思いついたので書いてみたのがこれ。
class Mid;
class MidSub {
std::string &str_;
std::string::size_type start_, len_;
public:
MidSub(std::string &to, std::string::size_type start,
std::string::size_type len) :
str_(to), start_(start), len_(len) { };
std::string &operator=(std::string &from) {
// 略
}
operator std::string() {
// 略
}
};
class Mid {
public:
MidSub operator() (std::string &to, std::string::size_type start,
std::string::size_type len) {
return MidSub(to, start - 1, len);
}
} mid;
mid.operator()()で処理用オブジェクトMidSubを生成するようになっている。何でこんな回りくどい事になっているかというと、mid(str, 1, 2) = "ほげ"の場合、普通にやるとmid(str, 1, 2)(多分operator()になるだろう)の戻り値に"ほげ"を代入する、という変な処理となってしまう為だ。
しかし、どうも『Midが実質的に何もしていない』『midがインスタンス』という点が気持ち悪いように思っていた。
ある日、C++を猛勉強していた某専門学校でのクラスメートYに(ネタとして)見せていると、偶然通りかかったM先生の目に止まる。
天井冴太『~でキモチワルイんですけど、どうにかなりませんかねぇ。』
M先生『なるよ』
天井冴太『(゚д゚)ナンダッテー』
いろいろ話をして、思いついたのがこれ。
class mid {
std::string &str_;
std::string::size_type start_, len_;
public:
mid(std::string &str, std::string::size_type start,
std::string::size_type len = std::string::npos)
: str_(str), start_(start - 1), len_(len) {
// 略
}
std::string &operator=(const std::string &from) { // [mid() = string] ver
// 略
}
operator std::string() const { // [string = mid()] ver
// 略
}
};
mid()を一時オブジェクト生成のシンタックスを利用するようにした。よくよく考えたら関数のシンタックスと同じなんじゃないか、これって。これによって、midを1つのクラスにまとめる事が出来た。
ひとつ残念だったのは、グローバルなoperator=()が記述できない点。どうやら言語仕様上そうなっているらしい。operator=(std::string, mid)を定義出来たらスッキリしたのだが……仕方が無いのでoperator std::string()を使っている。なので、下手したらキャストする必要が出てきてしまうが、それはまぁ、ご愛嬌という事で。
mid1.cpp、mid2.cppの最後の行にある#include "midtest.cpp"は今回のコードのテスト用のmainが書いてある。一応アップしたので、テスト用にどうぞ。
→midtest.cpp
