如何为std :: function类实现类型橡皮擦?

时间:2015-05-16 06:50:00

标签: c++ type-erasure std-function

我想在容器中放入几个方法指针,所以我实现了一个简单的std::function - 类似模板类:

template<typename ...Args>
class MethodHolder : MethodHolderBase
{
public:
    typedef void(*MethodType)(Args...);
    MethodHolder(MethodType method) : method(method) {}
    virtual ~MethodHolder() {}

    void Invoke(Args... args)
    { method(args...); }

private:
    MethodType method;
};

它有一个基类,所以我可以写这样的代码:

void func(int);
...
std::vector<MethodHolderBase*> funcs;
funcs.push_back(new MethodHolder<int>(&func));
...

然后我添加了一个包装来从Invoke()调用MethodHolderBase

class Method
{
public:
    ...//constructors, assignment operator, destructor
    template<typename ...Args>
    void Invoke(Args&&... args)
    {
        auto pHolder = dynamic_cast<MethodHolder<Args...>*>(pBase);
        if (pHolder)
            pHolder->Invoke(args...);
    }
private:
    MethodHolderBase* pBase;
}

现在,我可以在容器中放置一些Method实例,并调用Invoke()来调用函数。有效。但是,一旦我将func的声明更改为:

void func(int&&);

似乎无论我传递给Method::Invoke()哪种类型,都不会推断出int&&,因此dynamic_cast会失败。

我应该对Method::Invoke做一些修改吗?如果是这样,怎么样?或者有一个不同的解决方案?

1 个答案:

答案 0 :(得分:0)

您应该通过std::forward使用完美转发,否则您的右值/左值参考可能会被保留(有关更多信息see this beautiful answer):

void Invoke(Args&&... args)
//              ^^
{ method(std::forward<Args>(args)...); }
//       ^^^^^^^^^^^^^^^^^^^    ^

然后:

template<typename ...Args>
void Invoke(Args&&... args)
{
    auto pHolder = dynamic_cast<MethodHolder<Args&&...>*>(pBase);
    //                                           ^^
    if (pHolder)
        pHolder->Invoke(std::forward<Args>(args)...);
//                      ^^^^^^^^^^^^^^^^^^^    ^
}