标准的重载 `std::abs` 不匹配 `std::function`

huangapple go评论78阅读模式
英文:

Standard overloaded std::abs doesn't match std::function<double (double)>

问题

我遇到了以下错误

min.cpp:17:30: 错误: 无法将'<overloaded function type>'转换为'Container::UnaryFun'(即'function<double (double)>')
    this->addFunction("abs", abs);

当尝试编译以下代码时:

#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;
}

我尝试检查了std::abs 的声明,其参数为double,返回类型也为double,看起来是这样的:

inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
  return __builtin_fabs(__lcpp_x);
}

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

它只能用于double 类型。我通过添加以下代码来进行了检查:

double a = 5;
double b = std::abs(a);

它可以成功编译,没有任何问题或者转换警告。

我尝试声明自己的abs 函数如下:

inline double xabs(double val)
{
    return val < 0 ? -val : val;
}

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

this->addFunction("abs", xabs);

在这个更改之后,代码可以编译。

有什么想法,为什么使用std::abs 的代码无法编译?

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

Apple clang version 14.0.0 (clang-1400.0.29.202)
目标:x86_64-apple-darwin21.6.0
线程模型:posix
已安装目录:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

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

基于评论的更新

我进行了更深入的研究,似乎std::function 的声明方式存在问题,这导致了上述问题。

如果我将addFunction 声明如下,不使用std::function,问题就消失了。

auto addFunction(const std::string& name, double (*fun)(double)) -> void
{
}

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

英文:

I'm getting the following error

min.cpp:17:30: error: no viable conversion from &#39;&lt;overloaded function type&gt;&#39; to &#39;Container::UnaryFun&#39; (aka &#39;function&lt;double (double)&gt;&#39;)
    this-&gt;addFunction(&quot;abs&quot;, abs);

when trying to compile the following code:

#include &lt;cmath&gt;
#include &lt;string&gt;
#include &lt;functional&gt;

class Test
{
public:
  using UnaryFun  = std::function&lt;double (double)&gt;;

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

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

I've tried to check the declaration of std::abs for argument double and return type double and looks like this:

inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
  return __builtin_fabs(__lcpp_x);
}

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

It is accesible specifically for the double type. I've checked this by adding:

double a = 5;
double b = std::abs(a);

and this compiles without problems or conversion warnings.

I've tried to declare my own abs function like so:

inline double xabs(double val)
{
    return val &lt; 0 ? -val : val;
}

and then change the following code like so to use this new xabs instead of std::abs

this-&gt;addFunction(&quot;abs&quot;, xabs);

and after this change, the code compiles.

Any ideas why the code with std::abs doesn't compile?

My environment:
OS: Mac OS 12.6
Compiler:

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

Command to compile: g++ -std=c++2a -o min min.cpp

Update based on comments

I dug a bit deeper, and it seems that there is a problem with how std::function is declared, which led to the problem above.

If I declare addFunction like so, without std::function, the problem disappears.

  auto addFunction(const std::string&amp; name, double (*fun)(double)) -&gt; void
  {
  }

This means that the compiler cannot figure out the matching abs if std::function is used but it can identify the matching overload if the type of the function is described directly without std::function.

答案1

得分: 6

  1. Use a cast:
addFunction("abs", std::static_cast<double(*)(double)>(std::abs));
  1. Wrap it in a lambda:
addFunction("abs", [](double d) { return std::abs(d); });
  1. As you've done, wrap it in a non-overloaded function
英文:

The problem is that, since it has multiple overloads, std::abs doesn't have a single type. That means that the compiler can't select a std::function constructor to use to convert it since it can't deduce a type for the constructor's template parameter.

There are a couple of ways to get around that:

  1. Use a cast:
addFunction(&quot;abs&quot;, std::static_cast&lt;double(*)(double)&gt;(std::abs));
  1. Wrap it in a lambda:
addFunction(&quot;abs&quot;, [](double d) { return std::abs(d); });
  1. As you've done, wrap it in a non-overloaded function

huangapple
  • 本文由 发表于 2023年2月18日 09:31:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490629.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定