英文:
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 '<overloaded function type>' to 'Container::UnaryFun' (aka 'function<double (double)>')
this->addFunction("abs", abs);
when trying to compile the following code:
#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;
}
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 < 0 ? -val : val;
}
and then change the following code like so to use this new xabs
instead of std::abs
this->addFunction("abs", 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& name, double (*fun)(double)) -> 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
- Use a cast:
addFunction("abs", std::static_cast<double(*)(double)>(std::abs));
- Wrap it in a lambda:
addFunction("abs", [](double d) { return std::abs(d); });
- 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:
- Use a cast:
addFunction("abs", std::static_cast<double(*)(double)>(std::abs));
- Wrap it in a lambda:
addFunction("abs", [](double d) { return std::abs(d); });
- As you've done, wrap it in a non-overloaded function
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论