嵌套绑定表达式

2024-06-26

这是一个后续问题我之前的问题 https://stackoverflow.com/questions/2735294/templates-function-pointers-and-c0x.

#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++ 标头深处遇到编译错误:

functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested

func_wrapper(foo) 应该执行 func(doit(foo))。在实际代码中,它将函数打包以供线程执行。 func 是另一个线程执行的函数,doit 位于两者之间,检查未处理的异常并进行清理。但是 func_wrapper 中的额外绑定把事情弄乱了......


首先我先介绍一下2个要点:

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

  • b:使用 std::bind 无法将右值引用正确转发到函数。还有reason https://stackoverflow.com/a/4871563/2195556已经详细说明了。

那么,我们来看看这个问题。这里最重要的函数可能是 func_wrapper ,它旨在执行 3 个目的:

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

根据b点,目的1无法实现。因此,让我们忘记完美转发,doit 函数模板必须接受左值引用参数。

根据a点,目的2将通过使用std::ref来执行。

因此,最终版本可能是:

#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,该怎么办呢?尝试这个:

#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()。
  • 2个run()函数模板用于检查原始函子参数是否完美转发。
  • Dispatcher_traits 会将 bool 常量映射到类型。
  • 您最好将 Dispatcher::forward 命名为与 Dispatcher::dispatch 不同,否则您必须使用 Dispatcher::forward 的签名调用 std::bind 模板。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌套绑定表达式 的相关文章

  • 是否可以使静态控件透明?

    我正在尝试实现一个静态控件 该控件刷新 更改文本 以响应每秒发生一次的某个事件 由于我不想每秒绘制整个客户区域 所以我决定使用静态控件 现在的问题是父窗口被蒙皮 这意味着它有自定义位图作为背景 而静态控件没有适应 所以我正在寻找使静态控件的
  • 为什么更新外键后引用约束会不一致?

    抱歉 这个模糊的标题很难用一句话来描述 我有 2 个实体User and UserAddress 其中 User 有 2 个外键DefaultInvoiceAddressId and DefaultDeliveryAddressId和 Us
  • 如何使用 LINQ ForEach 更改 List

    我有一个List
  • gets 和 scanf 有什么区别?

    如果代码是 scanf s n message vs gets message 有什么区别 似乎两者都获取消息的输入 基本区别 参考您的特定场景 scanf 遇到一个时结束接受输入whitespace newline or EOF gets
  • OWIN AuthenticationOptions 在 mvc5 应用程序中运行时更新

    Hi 情况如下 我在 iis 7 上有一个带有 Identity 2 的 MVC 5 应用程序 该应用程序为多个网站提供服务 主机名是某些网站的关键 网站 另一个网站 等等 我决定在我的所有网站上使用谷歌外部登录 每个网站都应该是带有个人
  • 带方括号的 Uri.EscapeUriString

    这是一个奇怪的问题 但让我们看看它会得到什么样的回应 如果我编写一个控制台应用程序 VS 2013 NET 4 5 1 并执行这行代码 Uri EscapeUriString 我明白了 但是 如果我执行同样的事情 嗯 从技术上来说Uri E
  • 多态性中基类缺少虚拟析构函数 = 资源泄漏?

    我们知道 如果要多态地使用基类 则需要将基类的析构函数指定为 virtual 否则程序中可能会出现资源泄漏 因为只会调用基类析构函数 而不会调用派生对象析构函数 我们还知道构造函数 析构函数纯粹是初始化 未初始化构造 而operator n
  • 将标准库添加到C++ eclipse项目中

    一个 非常 新手 C 问题 有没有办法自动将标准库添加到 C eclipse 项目中 我安装了 CDT 主要功能插件 您可以手动添加 STL 标头的路径路径和符号 gt 包含选项卡 http help eclipse org galileo
  • 如何处理作为参数传递到方法中的 Lambda 表达式 - C# .NET 3.5

    我对 Lambda 表达式的了解有点不稳定 虽然我可以编写使用 Lambda 表达式 又名 LINQ 的代码 但我正在尝试编写自己的方法 该方法采用一些 Lambda 表达式类型的参数 背景 我正在尝试编写一个方法 该方法从任何其他对象类型
  • 使用私有构造函数的 C# 单元测试类?

    好吧 我刚刚收到一个作业 我必须对具有私有构造函数的类执行单元测试 现在 当所有方法也都是非静态时 我该如何在不初始化类的情况下进行单元测试 有什么方法可以对具有私有构造函数的类进行单元测试 无需反射 如果您无法将类公开 您仍然可以通过以下
  • 持续运行的 C# 代码 - 服务还是单独的线程?

    我有一个 NET 4 Web 应用程序 它有 3 个关联的独立项目 DAL BAL 和 UI 我正在使用实体框架进行数据库交互 我有代码循环遍历一堆数据库数据 根据找到的内容调用方法 然后更新数据库 我希望这段代码一直运行 同时 我希望用户
  • 第三方引用的 dll 未被复制来构建

    我有一个第三方 net dll 被我的 dll 类库项目 A 引用和使用 我的控制台应用程序项目 B 引用项目 A 我的问题是第三方 dll 没有被复制到控制台应用程序项目 B 的构建中 这里有什么问题呢 我的 dll 类库中引用的第三方
  • OpenMP 循环数组访问中的错误共享

    我想利用 OpenMP 来并行执行我的任务 我需要将数组的所有元素减去相同的数量并将结果写入另一个向量中 两个数组都是动态分配的malloc第一个填充了文件中的值 每个元素都有类型uint64 t pragma omp parallel f
  • 嘲笑会员用户

    我目前正在开发一个 asp net mvc 2 应用程序 它使用默认的 SqlMembershipProvider 进行身份验证 我已经实现了一个控制器方法 通过调用读取当前用户的 ProviderUserKeyMembership Get
  • 除法时的小数舍入误差 (C#)

    我基本上有四个数字 比如 100 200 300 400 我需要计算概率为 100 100 200 300 400 200 100 200 300 400 等等在 当我使用小数数据类型来存储这些概率时 由于舍入问题 它们不会达到 1 在不使
  • 如何进行平衡组捕获?

    假设我有这个文本输入 tes tR R abc aD mnoR xyz 我想提取 ff 输出 R abc R xyz D mnoR xyz R R abc aD mnoR xyz 目前 我只能使用平衡组方法提取组内的内容 如中所示msdn
  • PC 上 XNA 中的信箱和缩放

    有没有一种方法可以让我基本上以 1080p 或 720p 作为默认分辨率来开发 XNA 游戏 然后根据设置的分辨率将游戏中的所有内容缩放到适当的大小 而不必在每个 Sprite 中设置缩放因子Draw 方法 我的想法是 我可以基于 1080
  • 预览MouseMove 与 MouseMove

    我有相当多的 XAML 经验 但最近我注意到我的大多数同事都使用预览鼠标移动代替鼠标移动事件 我一直用鼠标移动它对我很有帮助 但我忍不住问我什么时候应该使用预览鼠标移动什么时候鼠标移动 有什么区别 各自有什么优点和缺点等等 PreviewM
  • 如何以一对一/零关系更新员工和身份用户

    我正在尝试更新员工记录 也想更新身份用户 如果我先单独更新身份用户 例如 UserManager Update user Context Entry employee State System Data Entity EntityState
  • Json.net 将数字属性序列化为字符串

    我正在使用 JsonConvert SerializeObject 序列化模型对象 服务器期望所有字段都是字符串 我的模型对象具有数字属性和字符串属性 我无法向模型对象添加属性 有没有办法将所有属性值序列化为字符串 我必须只支持序列化 而不

随机推荐