読者です 読者をやめる 読者になる 読者になる

自由を求めて、戻り値と引数を設定できるFunctionalVisitor

C++

進捗どうですか進捗だめです冬椿です。現実逃避して自由度の高いVisitorパターンを作ってました

ビジターパターンって

void accept(Visitor&visotor)

こんな感じ。自由度がない。戻り値戻せないし引数引けないし。籠のなかの小鳥のよーだ。ドレードレー

 

奴隷はいやなので色々して自由度の高いビジターパターンを目指してみた。引数も返り値もあるよ。やったね

イメージtemplateとか使ってこうしたい

R accept(Visitor&visotor,T...a)

こうしてみよー

Fuyutsubaki/FunctionalVisitor · GitHub

した

 

・よくあるディレクトリ構造とFunctionalVisitorのための前処理

using FileVisitor

    = FunctionalVisitor<class Files, class Dir, class File>;

struct Files :public FileVisitor::Root{ //Rootを継承するroot
    Files(const std::string&name)
        :name(name){}
    std::string name;
};
//Leafを継承して自身の型を入れるFile
struct File :public FileVisitor::Leaf<File>{ 
    File(const std::string& name, int size)
    :base_type(name), size(size){}
    int size;
};
//上に同じ
struct Dir :public FileVisitor::Leaf<Dir>{
    Dir(const std::string&name, const std::initializer_list<Files*>&list)
    :base_type(name), data(list){}
    std::vector<Files*>data;
};

 

で、こんな感じのディレクトリ構造があったとする

auto files = new Dir("新しいフォルダ1", {
        new Dir("新しいフォルダ1", { new File("txt.txt", 60), new File("gnp.png", 170) })
        , new Dir("新しいフォルダ2", { new File("exe.exe", 20), new File("gpj.jpg", 50) })
    });

 で、こうじゃ

struct Size{
        size_t operator()(const File&file){
            return file.size;
        }
        size_t operator()(const Dir&dir){
            size_t sum = 0;
            for (auto&x : dir.data)
                sum+=FileVisitor::apply_visitor<size_t>(*this,*x);
            return sum;
        }
};

std::cout << FileVisitor::apply_visitor<size_t>(Size(),*files)<< std::endl;

struct OutPut {
        void operator()(const File&file,size_t n){
            for (int i = 0; i < n; ++i)
                std::cout << '\t';
            std::cout <<file.name<<std::endl;
        }
        void operator()(const Dir&dir, size_t n){
            for (int i = 0; i < n; ++i)
                std::cout << '\t';
            std::cout << dir.name << std::endl;
            for (auto&x : dir.data)
                FileVisitor::apply_visitor<void>(*this, *x,n+1);   
        }
};

FileVisitor::apply_visitor<void>(OutPut(), *files, 0);

 

 

結果

300
新しいフォルダ1
        新しいフォルダ1
                txt.txt
                gnp.png
        新しいフォルダ2
                exe.exe
                gpj.jpg

 

いろいろboostのstatic_visitorに似てる。というより真似た。実装は読めなかったけど

なまえこそビジター名乗ってるけどじつはビジターしてない。ダブルディスパってない。でも動作自体はvisitorだしビジターでいいともう