嵌套绑定表达式 [英] Nested bind expressions

查看:74
本文介绍了嵌套绑定表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是对我之前的问题的后续问题.

#include <functional>

int foo(void) {return 2;}

class bar {
public:
    int operator() (void) {return 3;};
    int something(int a) {return a;};
};

template <class C> auto func(C&& c) -> decltype(c()) { return c(); }

template <class C> int doit(C&& c) { return c();}

template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }

int main(int argc, char* argv[])
{
    // call with a function pointer
    func(foo);
    func_wrapper(foo);  // error

    // call with a member function
    bar b;
    func(b);
    func_wrapper(b);

    // call with a bind expression
    func(std::bind(&bar::something, b, 42));
    func_wrapper(std::bind(&bar::something, b, 42)); // error

    // call with a lambda expression
    func( [](void)->int {return 42;} );
    func_wrapper( [](void)->int {return 42;} );

    return 0;
}

我在C ++标头中遇到了编译错误:

I'm getting a compile errors deep in the C++ headers:

功能:1137:错误:类型'int(*)()'表达式中对类型'int(&)()'的引用的初始化无效
functional:1137:错误:从'int'转换为非标量类型'std :: _ Bind< std :: _ Mem_fn< int(bar :: *)(int)>(bar,int)>'请求

func_wrapper(foo)应该执行func(doit(foo)).在实际代码中,它打包了要执行的线程的功能.func将由另一个线程执行该函数,doit位于两者之间以检查未处理的异常并进行清理.但是func_wrapper中的附加绑定使事情变得混乱了.

func_wrapper(foo) is supposed to execute func(doit(foo)). In the real code it packages the function for a thread to execute. func would the function executed by the other thread, doit sits in between to check for unhandled exceptions and to clean up. But the additional bind in func_wrapper messes things up...

推荐答案

在开始时,请允许我介绍两个关键点:

At the beginning, please let me introduce 2 key points:

  • a :使用嵌套std :: bind时,首先评估内部std :: bind,并且将在外部std :: bind处替换返回值被评估.这意味着 std :: bind(f,std :: bind(g,_1))(x)的执行方式与 f(g(x))相同.如果外部std :: bind需要函子而不是返回值,则内部std :: bind应该由std :: ref包装.

  • a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x) executes as same as f(g(x)) does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.

b :无法使用std :: bind将r值引用正确转发到函数.并且原因已经详细说明.

b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.

所以,让我们看一个问题.这里最重要的功能可能是func_wrapper,旨在执行3个目的:

So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:

  1. 首先完美地将函子转发到doit功能模板,
  2. 然后使用std :: bind将doit作为闭包,
  3. 并让func函数模板执行最后由std :: bind返回的函子.

根据点b,目的1无法实现.因此,让我们忘记完美的转发,并且doit函数模板必须接受l值参考参数.

According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.

根据点a,目的2将通过使用std :: ref来实现.

According to point a, purpose 2 will be performed by using std::ref.

结果,最终版本可能是:

As a result, the final version might be:

#include <functional>

int foo(void) {return 2;}

class bar {
public:
    int operator() (void) {return 3;};
    int something(int a) {return a;};
};

template <class C> auto func(C&& c) -> decltype(c()) { return c(); }

template <class C> int doit(C&/*&*/ c)    // r-value reference can't be forwarded via std::bind
{
    return c();
}

template <class C> void func_wrapper(C&& c)
{
    func(std::bind(doit<C>,
                   /* std::forward<C>(c) */ // forget pefect forwarding while using std::bind
                   std::ref(c)) // try to pass the functor itsself instead of its return value
        );
}

int main(int argc, char* argv[])
{
    // call with a function pointer
    func(foo);
    func_wrapper(foo);  // error disappears

    // call with a member function
    bar b;
    func(b);
    func_wrapper(b);

    // call with a bind expression
    func(std::bind(&bar::something, b, 42));
    func_wrapper(std::bind(&bar::something, b, 42)); // error disappears

    // call with a lambda expression
    func( [](void)->int {return 42;} );
    func_wrapper( [](void)->int {return 42;} );

    return 0;
}

但是,如果您真的要实现目标1和2,该怎么办?试试这个:

But, if you really want to achieve purpose 1 and 2, how? Try this:

#include <functional>
#include <iostream>

void foo()
{
}

struct bar {
    void operator()() {}
    void dosomething() {}
};

static bar b;

template <typename Executor>
void run(Executor&& e)
{
    std::cout << "r-value reference forwarded\n";
    e();
}

template <typename Executor>
void run(Executor& e)
{
    std::cout << "l-value reference forwarded\n";
    e();
}

template <typename Executor>
auto func(Executor&& e) -> decltype(e())
{
    return e();
}

template <bool b>
struct dispatcher_traits {
    enum { value = b };
};

template <typename Executor, bool is_lvalue_reference>
class dispatcher {
private:
    static void dispatch(Executor& e, dispatcher_traits<true>)
    {
        run(e);
    }

    static void dispatch(Executor& e, dispatcher_traits<false>)
    {
        run(std::ref(e));
    }

public:
    static void forward(Executor& e)
    {
        dispatch(e, dispatcher_traits<is_lvalue_reference>());
    }
};

template <typename Executor>
void func_wrapper(Executor&& e)
{
    typedef dispatcher<Executor,
                       std::is_lvalue_reference<Executor>::value>
        dispatcher_type;

    func(std::bind(&dispatcher_type::forward, std::ref(e)));
}

int main()
{
    func_wrapper(foo);   // l-value
    func_wrapper(b);  // l-value
    func_wrapper(bar());  // r-value
    func_wrapper(std::bind(&bar::dosomething, &b));  // r-value
    func_wrapper([](){});  // r-value
}

让我解释一些要点:

  • 要减少大量return语句,请将函子签名从int()更改为void().
  • 两个run()函数模板用于检查原始函子参数是否完美转发.
  • dispatcher_traits将映射bool常数以键入.
  • 最好将dispatcher :: forward命名为与dispatcher :: dispatch不同,或者您必须使用dispatcher :: forward的签名调用std :: bind模板.

这篇关于嵌套绑定表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆