【问题标题】:std::function vs. standard functionsstd::function 与标准函数
【发布时间】:2019-01-14 23:26:11
【问题描述】:

我在玩 function pointers vs. std::function 并遇到了以下问题。

让我们考虑以下代码:

#include <cmath>
#include <functional>

// g++ -std=c++17 SF.C -o SF
// clang++ -std=c++17 SF.C -o SF

int main()
{
    typedef double (*TpFunctionPointer)(double) ;

    TpFunctionPointer pf1 = sin;                     // o.k.
    TpFunctionPointer pf2 = std::sin;                // o.k
    TpFunctionPointer pf3 = std::riemann_zeta;       // o.k

    std::function< double(double) > sf1( sin );                // o.k
    std::function< double(double) > sf2( std::sin );           // fails
    std::function< double(double) > sf3( std::riemann_zeta );  // fails
}

使用g++ v8.2clang v7.0 编译对函数指针 pf1、pf2、pf3 和 sf1 效果很好。 但是对于 sf2 和 sf3 我会收到相当长的错误消息,例如:

SF.C:17:47: error: no matching function for call to ‘std::function<double(double)>::function(<unresolved overloaded function type>)’
  std::function< double(double)> sf2( std::sin );           // fails

这是预期的行为吗?
sf2sf3 不应该没问题吗?

【问题讨论】:

  • 实际上,即使是第一个对我来说也失败了(因此现在不是答案 + LRIO 所说的)
  • 有趣的是,这与几秒钟前提出的问题非常相关:stackoverflow.com/questions/54182502/…
  • 不同之处在于std::function的构造函数是模板化的,所以编译器没有上下文来推断重载。
  • 更有趣的是double (*pf4)(double) = static_cast&lt;float (*)(float)&gt;(std::sin); 不编译,但std::function&lt;double(double)&gt; sf4 (static_cast&lt;float (*)(float)&gt;(std::sin)); 可以。
  • @molbdnilo 在我的脑海中,我不记得这是多么明确。我的直觉告诉我这是一个“编译但不合法”的案例,但我几乎会把钱花在它是深奥的正确上。无论哪种方式都是不使用它的好理由 IMO!

标签: c++ std c++17


【解决方案1】:

multiple overloads of the &lt;cmath&gt; std::sin(有a template version in &lt;complex&gt;,但这不是你想要的),编译器不知道你想要哪一个,尽管事实上只有一个会成功绑定到你的std::function 类型!从这个意义上说,C++ 不会进行向后查找……

……除非它发生了! static_cast on a function pointer type 是一个例外,这正是您需要的:

std::function<double(double)> sf2(static_cast<double(*)(double)>(&std::sin));

the static_cast cppreference documentation page 上有一个例子。

对这个通用解决方案的一些潜在改进(感谢 Nathan 和 MSalters):

std::function<double(double)> sf2(static_cast<TpFunctionPointer>(&std::sin))

std::function<double(double)> sf2([](double val){ return std::sin(val); });

【讨论】:

  • 如果您不想记住函数指针语法,也可以使用[](double val){return std::sin(val);}
  • 建议:使用问题中的 typedef 解决方案可能更具可读性:std::function&lt;double(double)&gt; sf2(static_cast&lt;TpFunctionPointer&gt;(&amp;std::sin))
  • @MSalters 就是这样!
  • 感谢您的建议。
  • 我知道我可以解决使用 lambda 或强制转换的问题。 lambdas 的问题在于,您实际上在一段冗长的代码中隐藏了一个简单的赋值。此外,演员表使代码的可读性降低。我实际上想要三个参数特殊函数,如 assoc_laguerre 或 assoc_legendre,这使得这些解决方案的可读性更差。因此,我的问题是,这种行为是标准有意的并且有某种目的,还是只发生在 g++ 和 clang++ 的实现中。
猜你喜欢
  • 1970-01-01
  • 2018-06-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多