std :: bind与指向函数对象的指针

时间:2012-10-25 17:49:18

标签: c++ c++11 bind shared-ptr variadic-templates

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

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

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

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);

提前致谢。

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

2 个答案:

答案 0 :(得分:4)

如果我们为解除引用运算符设置了一个标准函数对象(很像std::plus<T>用于添加TT)那么我们可能会涉及一个嵌套的绑定表达式,但这不是情况 - 加上我们需要一个调用操作符,因为在嵌套绑定表达式的评估过程中发生的通常替换不适用于第一个参数!您的解决方案引入了额外的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);Here's a proof-of-concept也显示了如何妥善处理占位符。

我提到了上述解决方案,因为像calldereference这样的仿函数是有用的砖块 - 我个人在我的工具中使用它们。然而,我首选的解决方案是编写一个多态函数,它执行间接并一次调用:

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) }; }
实际上,您可以将{p>用作auto g = std::bind(make_indirect_callable(f), 0.0);

我应该提一下,与你的解决方案不同,那些需要在线外写一些类型。由于lambda表达式的固有局限性,这是一个不幸的情况。如果你想坚持你现在拥有的东西,我有一个小建议,在lambda内你std::forward<Args>(args)...参数。如果您处理仅移动类型,这可能会很有用。

答案 1 :(得分: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);