3

我正在尝试编写一个简单的函数来转换 std::function<> 对象,同时绑定最后一个参数。这就是我所拥有的:

template<typename R, typename Bind, typename ...Args> std::function<R (Args...)> bindParameter (std::function<R (Args..., Bind)> f, Bind b)
{
    return [f, b] (Args... args) -> R { return f (args..., b); };
}

这就是我想使用它的方式:

int blub (int a, int b)
{
    return a * b;
}

// ...

int main ()
{
    std::function<int (int, int)> f1 (blub);

    // doesn't work
    std::function<int (int)> f2 = bindParameter (f1, 21);

    // works
    std::function<int (int)> f3 = bindParameter<int, int, int> (f1, 21);

    return f2 (2);
}

...因此在此示例中,主函数应返回 42。问题是,gcc (4.6) 似乎无法正确推断模板参数的类型,第一个版本产生以下错误:

test.cpp:35:58: error: no matching function for call to 'bindParameter(std::function<int(int, int)>&, int)'
test.cpp:35:58: note: candidate is:
test.cpp:21:82: note: template<class R, class Bind, class ... Args> std::function<R(Args ...)> bindParameter(std::function<R(Args ..., Bind)>, Bind)

但在我看来,参数是显而易见的。还是这种类型的推断没有被标准覆盖或者还没有在 gcc 中实现?

4

2 回答 2

3

不能std::function用作函数模板的推导参数。由于没有可匹配的规则,因此无法以这种方式进行int(*)(int, int)扣除std::function<int(int, int)>。(还要考虑任何 std::function<Signature>有一个构造函数接受int(*)(int, int),即使在大多数情况下这会在实例化时导致错误。)

在一般情况下检测函子的签名是有问题的。甚至 KennyTM 的解决方案也有局限性:它检测单态函子和类似函数的东西的签名,但不适用于多态函子(例如重载operator())或具有代理调用函数的函子(即使在单态情况下)。

然而,由于decltype(或等效地,std::result_of)可以完全回避检测签名的问题,我建议这样做。因此,KennyTM 答案的变体:

template<typename Functor, typename Bound>
struct bind_last_type {
    Functor functor;
    Bound bound;

    template<typename... Args>
    auto operator()(Args&&... args)
    -> typename std::result_of<Functor&(Args..., Bound)>::type
    // equivalent:
    // -> decltype( functor(std::forward<Args>(args)..., std::move(bound)) )
    { return functor(std::forward<Args>(args)..., std::move(bound)); }
};

template<typename Functor, typename Bound>
bind_last_type<
    typename std::decay<Functor>::type
    , typename std::decay<Bound>::type
>
bind_last(Functor&& functor, Bound&& bound)
{ return { std::forward<Functor>(functor), std::forward<Bound>(bound) }; }
于 2011-11-18T07:57:33.497 回答
1

不确定推理,但如果我只定义一个模板化的函数对象,它就可以工作。

template <typename FType, typename LastArgType>
struct BindLastHelper
{
    FType _f;
    LastArgType _last_arg;

    template <typename... Args>
    typename utils::function_traits<FType>::result_type
        operator()(Args&&... args) const
    {
        return _f(std::forward<Args>(args)..., _last_arg);
    }
};

template<typename FType, typename LastArgType>
BindLastHelper<FType, LastArgType> bindParameter (FType f, LastArgType b)
{
    return BindLastHelper<FType, LastArgType>{f, b};
}

笔记:

于 2011-11-17T18:05:51.130 回答