【问题标题】:C++ std::bind to std::function, what went wrong in VS2015?C++ std::bind 到 std::function,VS2015 出了什么问题?
【发布时间】:2018-11-29 17:32:49
【问题描述】:

我是 VS2013 的用户,我经常使用如下初始化,它的工作就像一个魅力:

MyClass::MyClass myRoutine(){
    std::function<double(double)> oFunc = std::bind(&Myclass::myfunction, this, std::placeholders::_1);
}

MyClass::MyClass myfunction(double & inX){
    return 0;
}

我决定升级到VS2015,但是编译器报错:

错误 C2440: 'initializing': 无法从 'std::_Binder<:_unforced myclass:: std::_ph> & 转换>' 到 'std::function'

发生了什么?

【问题讨论】:

  • 为什么要把double(double &amp;)函数放到double(double)中?另外,你为什么使用bind 而不是 lambda? Lambda 更好,更容易调试和编译成更好的代码。
  • 我使用bind的唯一原因是因为它在VS2013中工作......当然,如果有更好的方法,我正在听
  • 我很确定 VS2013 也支持这一点:... oFunc = [this](double &amp;x){ return myfunction(x); };。如果你愿意,我可以把它变成一个答案。
  • 一个解释为什么它在 VS2013 中工作的答案,以及更好的编写方式将受到欢迎
  • 为什么有效? Lambdas 还是你的旧代码?

标签: c++ c++11 visual-studio-2015 visual-studio-2013 stl


【解决方案1】:

函数签名不匹配:double(double)double(double&amp;)。因此编译错误。其中一项需要更改,例如:

double MyClass::myfunction(double inX){
    return 0;
}

【讨论】:

    【解决方案2】:

    您的函数通过引用 (double &amp;) 获取其参数,而您尝试将其分配给具有按值获取签名 (double) 的函数。

    这很可能是由于一致性错误(可能是与非常量引用到临时 MSVC 扩展的一些奇怪的交互)在 VS2013 中编译的。基本上它不是有效的 C++ 代码。 VS2015 在标准支持和一致性方面领先于以前的 VS(VS2017 更是如此),因此不再编译此错误代码。

    无论如何,std::bind 几乎完全被 lambdas 淘汰了,VS2010+ 应该支持它。它们产生更好的代码、更好的警告/错误、更容易编写和调试。

    例如,您的代码可以'这样重写:

    std::function&lt;double(double)&gt; oFunc = [this](double x){ return myfunction(x); };

    如果你真的想通过引用传递,或者像这样:

    std::function&lt;double(double &amp;)&gt; oFunc = [this](double &amp;x){ return myfunction(x); };

    请注意它是多么的短和简单。

    【讨论】:

    • Lambdas 适用于单行函数。当你想要一个包含更多代码的函数时,你会怎么做?有一个简单地调用另一个函数的 lambda?如果你打算这样做,你不妨使用 std::bind。或者也许把完整的函数放在 lambda 中。这非常令人困惑,在另一个函数中定义了一个函数!
    • @AlastairG “如果你打算这样做,你不妨使用 std::bind。”为什么?正如这个(以及许多其他类似的问题,更不用说一般经验)所示,更好的方法是“如果你有 std::bind,你不妨替换它 lambda”。 Lambda 方法更易于阅读和理解,通常更短,生成更好的代码,避免一致性错误并生成合理的错误消息(编译速度更快,启动更灵活)。那里有一个非常小的利基市场,std::bind 仍然有用(甚至这是有争议的)。
    • 每当我阅读任何语言的带有 lambda 的代码时,只有当您可以将 lambda 放在很少的几行上并且所有代码都不需要任何上下文时,它才可读。使用成员变量的更复杂的类函数很难写成 lambda 表达式,而且不可读。或者至少使用我曾经被要求编码的任何缩进/样式。从本质上讲,我发现 lambdas 很难或不可能阅读,特别是如果它们有任何复杂性。您基本上是在函数调用中编写函数!像 `RegisterForEventX(my_callback) 这样的简单调用非常易读。
    • @AlastairG std::bind 不生成函数指针。它生成未指定类型的“绑定表达式”。它充其量只是一个带有额外堆栈帧的仿函数,但通常情况会更糟,因为所有 TMP 都使它对编译器不透明。另一方面,编译器对 Lambda 进行了相当好的优化。请注意,在一般情况下(您需要将此指针存储在某处),无法避免这种情况的额外间接性,例如 OP 中的情况(您需要将此指针存储在某处),但 lambda 仍然提供更好的代码生成:godbolt.org/z/bj8Wff。顺便说一句,clang 能够完全优化它,令人印象深刻!
    • 非常有说服力。谢谢你花时间解释它。我真的很感激。
    猜你喜欢
    • 2021-09-18
    • 1970-01-01
    • 2019-02-20
    • 2022-11-04
    • 2016-12-18
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多