最近、DI覚えました。真に作りたい機能に集中して作れるのはとってもいいもんです。
で、ちょっとしたCSVパーサーを作ってた時のこと。CSVを読み込むにも、ファイルからなのかWEB上からなのか、そもそも文字コードの問題もあるわけです。
そんなことをいちいちパーサーに書きたくない。そこで、読み込み部分はIRepositoryというインターフェースにして疎結合を目指そうとしました。疎結合あるあるですね。
そんな感じでザッと書いたコードがこんな感じ。
#include <iostream>
using namespace std;
class IRepository
{
public:
virtual string GetText() const = 0;
};
class CSVParser
{
public:
CSVParser(const IRepository &repository){/*なんやかんや*/}
const char *Value(int row,int col){return "なんやかんや";}
};
class TempRepo : public IRepository
{
public:
string GetText() const {return string("ねこ,にゃーん\ncat,meow");}
};
int main(void){
CSVParser parser(TempRepo());
cout << parser.Value(0,1); //(1)
return 0;
}
具体的なパーシングは省略しましたが、適当なCSV文字列を一旦TempRepoに持たせて、その文字列のカンマや改行が適切に解釈され、(1)の部分で「にゃーん」と表示されるはず。
しかし、この行で「式にはクラス型が必要です。」のようなエラーが出てビルドさせてくれません。つまりparserがCSVParser型と認識してないんです。
ところで、クラスを引数なしコンストラクタで初期化して使うときは()を書いてはいけません。
CSVParser parser(); //エラー
CSVParser parser; //OK
()を書くと関数宣言とみなされ、意味合いが違ってきます。
症状としては近いのですが、今回は引数ありです。うーん。
CSVParser parser = CSVParser(TempRepo());
これは通りました。
じゃ、試しにキャストしてみるか。
CSVParser parser((const IRepository &)TempRepo());
通った
ここに強く深く刻む わすれられぬように