melt日記

.NETすらまともに扱えないへたれのページ

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  111  : 記事  3  : コメント  8241  : トラックバック  41

ニュース

わんくま同盟

わんくま同盟

C# と VB.NET の質問掲示板

iKnow!


Dictation



書庫

C++ で、似たような処理だけれども関数の引数の数や型が違うせいでその処理をひとまとめにすることが出来ない、ということがあったりしませんか?

自分はよくありました。例えば以下のようなコードです。


// Hoge::FuncA の合計を返す。
// ただし Hoge::FuncA の結果がマイナスだった場合は
// その時点での合計を返す。
int FuncA(Array<Hoge*> array, int a, int b)
{
    int count = 0;
    for (int i = 0; i < array.length(); i++)
    {
        int result = array[i]->FuncA(a, b);
        if (result < 0)
        {
            break;
        }
        count += result;
    }
    return count;
}

// Hoge::FuncB の合計を返す。
// ただし Hoge::FuncB の結果がマイナスだった場合は
// その時点での合計を返す。
int FuncB(Array<Hoge*> array, double a, int b, float c)
{
    int count = 0;
    for (int i = 0; i < array.length(); i++)
    {
        int result = array[i]->FuncB(a, b, c);
        if (result < 0)
        {
            break;
        }
        count += result;
    }
    return count;
}

// 以下似たような関数がいっぱい続く
...

これらの関数は処理が似ているので何とかまとめたいのですが、関数名や引数の数が違うため、簡単にはできません。


そこで使えるのが Boost.Bind と Boost.Function。

これらを使うと、次のように実装することが出来ます。

int GenericFunc(Array<Hoge*> array, boost::function1<int, Hoge*> func)
{
    int count = 0;
    for (int i = 0; i < array.length(); i++)
    {
        int result = func(array[i]);
        if (result < 0)
        {
            break;
        }
        count += result;
    }
    return count;
}

int FuncA(Array<Hoge*> array, int a, int b)
{
    // Hoge::FuncA の a, b は bind して、Hoge*(this) は bind しない
    return GenericFunc(array,
        boost::bind(&Hoge::FuncA, _1, a, b));
}

int FuncB(Array<Hoge*> array, double a, int b, float c)
{
    // Hoge::FuncB の a, b, c は bind して、Hoge*(this) は bind しない

    return GenericFunc(array,
        boost::bind(&Hoge::FuncB, _1, a, b, c));
}
// 以下似たような関数が続く
...

GenericFunc の中に共通の処理が入りました。

boost::bind で引数を閉じこめる(束縛する)ことによって、GenericFunc を共通の処理に落とし込んでいます。


「こんなケース滅多にないよ!」とか思うかもしれませんが、例えばキューにメンバ関数(もしくは普通の関数)を詰めて定期的に実行するようなクラスが欲しくなることはよくあると思います(あるよね?)。

普通に実装しようとすると、

struct Function
{
    Function(void (Hoge::*pf)(int, int), Hoge* ph, int _a, int _b)
        : pFunc(pf), pHoge(ph), a(_a), b(_b) { }
    void (Hoge::*pFunc)(int a, int b); // 関数

    Hoge* pHoge; // this ポインタ
    int a; // 引数1
    int b; // 引数2
};
std::queue<Function> functionQueue;


// 定期的に実行される関数
void Invoke()
{
    if (functionQueue.empty()) return;
    Function f = functionQueue.front();
    functionQueue.pop();
    (f.pHoge)->*f.pFunc(f.a, f.b);
}

// 関数をキューに詰める
functionQueue.push(Function(&Hoge::FuncA, &hoge, 10, 20));

// Hoge::FuncB は引数の型と数が違うので入らない
// functionQueue.push(Function(&Hoge::FuncB, &hoge, 10.0, 20, 30.0));

こんな感じになるんじゃないかと思います。

この場合、関数の引数は固定だし Hoge クラスのメンバ関数に対してしか使えないし、あまり汎用的ではないです。

インターフェースを使えばもっとスマートになりますが、その方法は恐らく1つの処理に対して1つのクラスを割り当てることになると思うので、それではかなり手間が掛かってしまいます。


Boost.Bind と Boost.Function を使えば、こんな感じになります。

std::queue<boost::function0<void> > functionQueue;

// 定期的に実行される関数
void Invoke()
{
    if (functionQueue.empty()) return;
    boost::function0<void> f = functionQueue.front();
    functionQueue.pop();
    f();
}


// 関数をキューに詰める
functionQueue.push(boost::bind(&Hoge::FuncA, &hoge, 10, 20));
// Hoge::FuncB も詰めることが出来る
functionQueue.push(boost::bind(&Hoge::FuncB, &hoge, 10.0, 20, 30.0));

// Hoge クラスじゃなくても、関数なら何でも OK
functionQueue.push(boost::bind(&Fuga::FuncC, &fuga, 100));

何でも格納できる汎用的なファンクションキューの出来上がりです。


Boost.Bind と Boost.Function の組み合わせはほんと凶悪だと思います。

是非とも使ってみて下さい。

投稿日時 : 2008年1月31日 14:26

コメント

# re: [C++]Boost.Bind & Boost.Function 2008/01/31 15:52 アキラ
ファンクションキューいいなー

# re: [C++]Boost.Bind & Boost.Function 2008/01/31 17:26 melt
マルチスレッド用のキュークラスを作ると、ファンクションキューが大活躍しますよw

# JoQZIoWyGSw 2011/12/27 19:07 http://www.spytown.com/
Somewhere in the Internet I have already read almost the same selection of information, but anyway thanks!!...

# GfayCSvsaudvBgWbVXk 2011/12/29 20:28 http://www.healthinter.org/health/page/protonix.ph
Author, Shoot yourself a knee..!

# NCrEpbuNlmNPsABY 2012/01/07 8:49 http://www.luckyvitamin.com/m-153-garden-of-life
Comrade kill yourself.

# re: Ruby で数値を 0 埋めする 2019/01/24 13:39 zzyytt
http://www.adidas-tubular.us.com
http://www.adidassuperstar.us.com
http://www.michael-korsoutlets.us
http://www.reebokoutlet.us.org
http://www.nikeairmax2019.us.com
http://www.yeezyadidas.us.com
http://www.kyrieirving-shoes.us.com
http://www.kobesneakers.com
http://www.coachsonline.us.com
http://www.kd11.us
http://www.coachoutletstorefactory.com
http://www.adidaszxflux.com
http://www.filashoes.org
http://www.chromeheartsoutletonline.com
http://www.adidasyeezy500.us.com
http://www.hermeshandbags.us.org
http://www.adidasultraboost.us.org
http://www.outletlacoste.us.com
http://www.adidas-pureboost.us.com
http://www.coachoutlets.name


# TglGPQYJuFv 2022/04/19 9:49 johnansaz
http://imrdsoacha.gov.co/silvitra-120mg-qrms

Post Feedback

タイトル
名前
Url:
コメント