标准重载的 std::abs 与 std::function<double (double)> 不匹配

RAl*_*len 3 c++ macos g++ std

我收到以下错误

min.cpp:17:30: error: no viable conversion from '<overloaded function type>' to 'Container::UnaryFun' (aka 'function<double (double)>')
    this->addFunction("abs", abs);

Run Code Online (Sandbox Code Playgroud)

当尝试编译以下代码时:

#include <cmath>
#include <string>
#include <functional>

class Test
{
public:
  using UnaryFun  = std::function<double (double)>;

  Test()
  {
    this->addFunction("abs", abs);
  }
  auto addFunction(const std::string& name, UnaryFun fun) -> void
  {
    // ...
  }
};

auto main() -> int {
  Test eval;
  return 0;
}

Run Code Online (Sandbox Code Playgroud)

我尝试检查std::absfor 参数double和返回类型的声明double,如下所示:

inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
  return __builtin_fabs(__lcpp_x);
}
Run Code Online (Sandbox Code Playgroud)

/usr/local/Cellar/llvm/15.0.7_1/include/c++/v1/stdlib.h

它是专门针对该double类型的。我已经通过添加检查了这一点:

double a = 5;
double b = std::abs(a);
Run Code Online (Sandbox Code Playgroud)

并且编译时没有问题或转换警告。

我尝试abs像这样声明我自己的函数:

inline double xabs(double val)
{
    return val < 0 ? -val : val;
}
Run Code Online (Sandbox Code Playgroud)

然后像这样更改以下代码以使用这个新的xabs而不是std::abs

this->addFunction("abs", xabs);
Run Code Online (Sandbox Code Playgroud)

进行此更改后,代码可以编译。

有什么想法为什么代码std::abs无法编译吗?

我的环境: 操作系统:Mac OS 12.6 编译器:

Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Run Code Online (Sandbox Code Playgroud)

编译命令:g++ -std=c++2a -o min min.cpp

根据评论更新

我深挖了一下,似乎是std::function声明方式有问题,才导致了上面的问题。

如果我addFunction像这样声明,没有std::function,问题就消失了。

  auto addFunction(const std::string& name, double (*fun)(double)) -> void
  {
  }
Run Code Online (Sandbox Code Playgroud)

这意味着编译器无法确定是否使用了匹配的absif std::function,但如果直接描述函数的类型而不使用 ,它可以识别匹配的重载std::function

Mil*_*nek 6

问题是,由于它有多个重载,因此std::abs没有单一类型。这意味着编译器无法选择std::function用于转换它的构造函数,因为它无法推断构造函数的模板参数的类型。

有几种方法可以解决这个问题:

  1. 使用强制转换:
addFunction("abs", std::static_cast<double(*)(double)>(std::abs));
Run Code Online (Sandbox Code Playgroud)
  1. 将其包装在 lambda 中:
addFunction("abs", [](double d) { return std::abs(d); });
Run Code Online (Sandbox Code Playgroud)
  1. 正如您所做的那样,将其包装在非重载函数中

  • `std::abs` 不可寻址。第一个片段是错误的,尽管我不确定它有多糟糕。 (2认同)