5

给定一个指向函数对象的指针:

std::shared_ptr<std::function<double(double)>> f;

std::bindC++11 中是否有允许在语句中使用此指针的内置结构?例如:

std::function<double()> g = std::bind(built_in(f), 0.0);

我正在做的是使用可变参数模板

template<typename Ret, typename... Args>
std::function<Ret(Args...)> get_fn(const std::shared_ptr<std::function<Ret(Args...)>>& f)
{
    return [=](Args... args) -> Ret { return (*f)(args...); };
}

这让我可以写:

std::function<double()> g = std::bind(get_fn(f), 0.0);

提前致谢。

编辑:我应该更清楚。我需要在共享指针中使用函数对象的实例来进行优化。

4

2 回答 2

4

如果我们有一个用于取消引用运算符的标准函数对象(很像std::plus<T>添加Twith T),那么我们可以涉及一个嵌套的绑定表达式,但情况并非如此——另外我们需要一个调用运算符,因为通常的替换需要在评估嵌套绑定表达式期间放置的位置不适用于第一个参数!您的解决方案引入了一个额外的std::function,所以我提出了一些没有的替代方案。

编写您自己的调用和取消引用运算符:

struct call {
    template<typename Callable, typename... Args>
    auto operator()(Callable&& callable, Args&&... args) const
    // don't use std::result_of
    -> decltype( std::declval<Callable>()(std::declval<Args>()...) )
    { return std::forward<Callable>(callable)(std::forward<Args>(args)...); }
};

struct dereference {
    template<typename T>
    auto operator()(T&& t) const
    -> decltype( *std::declval<T>() )
    { return *std::forward<T>(t); }
};

template<typename IndirectCallable, typename... Args>
auto indirect_bind(IndirectCallable&& f, Args&&... args)
-> decltype( std::bind(call {}
                       , std::bind(dereference {}, std::declval<IndirectCallable>())
                       , std::declval<Args>()... ) )
{ return std::bind(call {}
                   , std::bind(dereference {}, std::forward<IndirectCallable>(f))
                   , std::forward<Args>()... ); }

然后你就可以做到了auto g = indirect_bind(f, 0.0);这是一个概念验证,它还显示了如何正确处理占位符。

我提到上述解决方案是因为函子喜欢call并且dereference是有用的积木——我个人将它们放在我的工具中。然而,我首选的解决方案是编写一个多态仿函数,它可以一次性完成间接调用:

template<typename Indirect>
struct indirect_callable_type {
    // Encapsulation left as an exercise
    Indirect f;

    template<typename... Args>
    auto operator()(Args&&... args)
    // don't use std::result_of
    -> decltype( std::declval<Indirect&>()(std::declval<Args>()...) )
    { return f(std::forward<Args>(args)...); }

    template<typename... Args>
    auto operator()(Args&&... args) const
    // don't use std::result_of
    -> decltype( std::declval<Indirect const&>()(std::declval<Args>()...) )
    { return f(std::forward<Args>(args)...); }

    // Lvalue and rvalue *this version also left as an exercise
};

template<typename T>
indirect_callable_type<typename std::decay<T>::type>
make_indirect_callable(T&& t)
{ return { std::forward<T>(t) }; }

事实上,你可以使用 as auto g = std::bind(make_indirect_callable(f), 0.0);

我应该提到,与您的解决方案不同,这些需要编写一些离线类型。由于 lambda 表达式的固有限制,这是一种不幸的情况。如果你想坚持你目前拥有的,我有一个小建议,那就是在 lambda 中你std::forward<Args>(args)...的参数。如果您曾经处理过仅移动类型,这可能会很有用。

于 2012-10-25T21:11:30.107 回答
3

您可以在这里使用一个不错的小技巧,即INVOKE 在指向成员函数的指针上,当传递一个指针或(甚至)一个智能指针(20.8.2p1 第二个项目符号,定义INVOKE)时,会自动间接间接其对象参数:

#include <functional>
#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<std::function<double(double)>> f
        = std::make_shared<std::function<double(double)>>(
            [](double d) { return d + 10.0; });
    std::function<double()> g = std::bind(
        &std::function<double(double)>::operator(), f, 0.0);
    std::cout << g() << std::endl;
}

如果您不想明确提及的类型f

std::function<double()> g = std::bind(
    &std::remove_reference<decltype(*f)>::type::operator(), f, 0.0);
于 2012-10-25T22:15:09.697 回答