std::mem_fun_ref関数を自作する

前回の記事でstd::mem_fun_ref関数というのを習いました。

多分処理的には難しいことはしてないだとうと思い、何も見ずに自作してみました。

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using std::cout; using std::endl;

template <class T>
class CMyMemFunRef {
public:
    CMyMemFunRef(const T func) {
        m_func = func;
    }
    template<class U> void operator()(const U& obj) {
        (obj.*m_func)();
    }
private:
    T m_func;
};

template<class T> CMyMemFunRef<T> mymem_fun_ref(const T func) {
    return CMyMemFunRef<T>(func);
}

class CSample {
public:
    CSample(int num) { m_num = num; }
    void output () const {
        cout << "CSapmle::output m_num = " << m_num << endl;
    }
private:
    int m_num;
};

int main () {
    std::vector<CSample> v;
    
    for(int i=0;i<5;++i) {
        v.push_back(CSample(i));
    }
    
    std::for_each(v.begin(),v.end(),mymem_fun_ref( &CSample::output ));
    
    return 0;
}
$ main
CSapmle::output m_num = 0
CSapmle::output m_num = 1
CSapmle::output m_num = 2
CSapmle::output m_num = 3
CSapmle::output m_num = 4

思ったよりも難しかったですorz

やはり頭の中でテキトーに考えてる内容と、実際に手を動かしてプログラミングしてみた内容とでは天と地ほどの差がありますね。もっともっとコードを書かないとダメだと実感しました。

ちなみに軽くコードの説明をしてみたいと思います。

まずmymem_fun_ref関数の引数ですが、メンバ関数のポインタを渡してるにも関わらず、「const T func」だけでうまく動いています。

これは関数テンプレートの型推論といい、前にコメント欄で教えていただいたものです。

次に、CMyMemFunRefクラスの関数演算子オーバーロードの部分はメンバ関数テンプレートになっています。これに気付くまで時間がかかりました。

当初CMyMemFunRefのテンプレート引数を二つにしてみたり、そうするとmymem_fun_refでの戻り値まで引数が二つになるのでどうすればいいのか悩んだりあれこれ試してました。なんか途中わけがわからなくなって

template<class T> CMyMemFunRef<T> mymem_fun_ref(T* func) {
    return CMyMemFunRef<T,typeid(T*).name()>(func);
}

とか

template<class T> CMyMemFunRef<T> mymem_fun_ref(const void (T::*func)() const ) {
    return CMyMemFunRef<T>(func);
}

とか書いたりして意味不明なコードを書いてました。

よくよく見ればどう考えてもおかしなコードなのに何でこんなの書いたのか自分でもわかりません^^;

やはり少し頭でっかちに覚えてしまっている可能性がありますね、何せC言語の勉強始めてからここまで約2ヶ月しか経っていないので勉強ばっかであまり実際のコードを書いて無いのでちょっとまずいかもしれません。

今後はもっと何かを作るということも意識したいと思います。