【问题标题】:Generic function pointer in C++11C++11 中的泛型函数指针
【发布时间】:2012-11-29 09:32:58
【问题描述】:

我目前正在用 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);

到目前为止,我的代码如下所示:

队列.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();
}

队列.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() 的函数可以采用任意数量的参数。是否有通用指针类型(它不一定是可执行的,只要我重复将相同的函数推送到队列时保持相同)可以做到这一点?

【问题讨论】:

    标签: c++ c++11 function-pointers


    【解决方案1】:

    根据 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确实是一个指向成员函数的指针;如果用户尝试传递一些其他可调用对象,那么这将中断。

    【讨论】:

      【解决方案2】:

      std::function::target&lt;&gt;() 可用于检查包装函数类型:

      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 对象包装的函数的类型与F 不同,std::function::target() 将返回nullptr

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-15
        • 2012-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多