5

現在、C++x0でメソッド実行キューを作成中です。push()基本的なキューメカニズムを実装して検証しましたが、特定のメソッドへの以前のすべての呼び出しを自動的に削除するオプションを使用して修正したいと思います。

queue.push(this, &Obj::foo, 1);
queue.push(this, &Obj::foo, 2);
queue.push(this, &Obj::foo, 3);

単に呼び出すのと同じである必要があります

queue.push(this, &Obj::foo, 3);

これまでの私のコードは次のようになります。

Queue.h:

#pragma once

#include <functional>
#include <vector>

using std::vector;
using std::function;
using std::bind;

class Queue
{

    private:
        struct functioncall {
            std::function<void()> call;
        };

        vector<functioncall> queue;

    public:
        Queue();
        ~Queue();

        template<typename T, typename F, typename... Args>
        int push(T, F , Args... args);

        int pop();
        bool empty();
        size_t size();
};


template<typename T, typename F, typename... Args>
int Queue::push(T instance, F func, Args... args)
{
    functioncall newelem = { bind(func, instance, args...) };
    queue.push_back(newelem);
    return queue.size();
}

Queue.cpp:

#include "Queue.h"

Queue::Queue() : queue()
{
}

Queue::~Queue()
{
    delete &queue;
}

int Queue::pop()
{
    if(!queue.empty())
    {
        queue.front().call();
        queue.erase(queue.begin());
        return queue.size();
    }
    return 0;
}

bool Queue::empty()
{
    return queue.empty();
}

size_t Queue::size()
{
    return queue.size();
}

結果を保存するだけでなく、呼び出されているメソッドへのポインターも保存して、そのポインターを探して古いエントリを削除しqueueたい構造体を取得するためのベクトルを既に準備しました。std::bind

問題は、渡される関数がpush()任意の量の引数を取ることができるということです。それを実行できる汎用ポインタータイプ(実行可能である必要はありません。同じ関数をキューに繰り返しプッシュする場合は同じです)はありますか?

4

2 に答える 2

5

5.2.10p10に従って、メンバー関数T::*(A1, A2, ...)へのポインターをメンバー関数タイプへの別のポインターにキャストしU::*(B1, ...)、情報を失うことなく元に戻すことができます。std::lessポインターをメンバー関数と比較できるため、ダミーのポインターからメンバーへの型にキャストすることで、void (Impl::*)()ポインターを同じシグニチャーを持つメンバー関数と比較できます。

ただし、異なるシグニチャを持つメンバー関数へのポインタが、メンバータイプへの同じポインタにキャストされたときに異なる比較になるとは限らないため、同等のタイプでシグニチャをエンコードする必要があります。 typeidここで動作します:

auto key = std::make_pair(&typeid(F), reinterpret_cast<void (Queue::*)()>(func));

Fこれは、それが実際にメンバー関数へのポインターであることを前提としています。ユーザーが他の呼び出し可能なオブジェクトを渡そうとすると、これは壊れます。

于 2012-11-29T09:51:05.553 に答える
3

std::function::target<>()ラップされた関数の型をチェックするために使用できます:

template <class F> bool is_same_call(const functionalcall& prevCall, F newCall)
{
   const F* pf = prevCall.call.target<F>();
   return pf ? *pf == newCall : false;
}

オブジェクトでラップされた関数の型が と異なる場合、std::function::target()が返されることに注意してください。nullptrstd::functionF

于 2012-11-29T10:50:49.717 に答える