我知道这是一个非常古老的话题,但我不明白为什么它在这里表现得如此。
该程序:
#include <vector>
#include <algorithm>
#include <cmath>
int main()
{
std::vector<double> a = {1,4,9,16};
std::transform(a.begin(), a.end(), a.begin(), sqrt); // WORKS
std::transform(a.begin(), a.end(), a.begin(), std::sqrt); // compilation error
}
Run Code Online (Sandbox Code Playgroud)
编译错误是
g++ -std=c++17 -O3 main.cpp -Wall -Wextra -pedantic
main.cpp: In function ‘int main()’:
main.cpp:10:57: error: no matching function for call to ‘transform(std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, <unresolved overloaded function type>)’
std::transform(a.begin(), a.end(), a.begin(), std::sqrt); // compilation error
^
........
Run Code Online (Sandbox Code Playgroud)
所以,万一
sqrt 编译器可以推导出参数/返回类型并使用此函数。std::sqrt编译器无法在std::sqrt?.. 的不同重载之间进行选择。为什么会这样?编译时所有类型都是已知的,它到底不能推断出什么?为什么只是简单的sqrt作品(我找不到定义)?
以下可能表明正在发生某些事情:
g++ -std=c++17 -O3 main.cpp -Wall -Wextra -pedantic
main.cpp: In function ‘int main()’:
main.cpp:10:57: error: no matching function for call to ‘transform(std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, <unresolved overloaded function type>)’
std::transform(a.begin(), a.end(), a.begin(), std::sqrt); // compilation error
^
........
Run Code Online (Sandbox Code Playgroud)
当它说它不能理解std::sqrt没有上下文的类型时,这是有道理的。
所以,从这个剪断它可能遵循sqrt声明 smth 像
#include <cmath>
int main()
{
typeid(sqrt); // compiles
typeid(std::sqrt); // compilation error
}
Run Code Online (Sandbox Code Playgroud)
whilestd::sqrt有许多重载,如https://en.cppreference.com/w/cpp/numeric/math/sqrt所示。
所以,我的问题是三重的:
std::时只是使用 ADL 或 smth 来找到它。另外,我不包括<math.h>.sqrt在某些库中定义了这种情况,但我想要标准版本,如何处理?std::sqrt如果已知,为什么不能推导出参数/返回类型?错误消息的关键部分是“<未解析的重载函数类型>”。有多个版本std::sqrt采用不同的参数类型,编译器无法知道在该上下文中您需要哪一个。
显然,在全局命名空间中,您的编译器提供了 C 名称:
float sqrtf(float);
double sqrt(double);
long double sqrtl(long double);
Run Code Online (Sandbox Code Playgroud)
只有一个名为 的函数sqrt,因此编译器知道要使用哪一个。
在std命名空间中还有更多:
float sqrt(float); // 1
float sqrtf(float);
double sqrt(double); // 2
long double sqrt(long double); // 3
long double sqrtl(long double);
double sqrt(Integral type); // 4
Run Code Online (Sandbox Code Playgroud)
所以有四个名为 的函数std::sqrt,编译器没有任何规则可以选择一个。
要选择重载,您可以使用演员表(是的,这很不直观,而且坦率地说,很奇怪):
std::transform(a.begin(), a.end(), a.begin(), (double (*)(double))std::sqrt)
Run Code Online (Sandbox Code Playgroud)
请注意,标记为“WORKS”的版本只能偶然使用。C++ 中不要求全局命名空间只有C 名称。
全局数学函数是否在某处声明?我想当你在没有它的情况下使用它时,
std::只需使用 ADL 或 smth 来找到它。另外,我不包括<math.h>.
<cmath>因此,可能会或可能不会包含<math.h>和公开 C函数。sqrt这就是您的实施正在做的事情。
sqrt如果在某个库中定义了,但我想要标准版本,该如何处理?
如果你愿意std::sqrt,那就用吧std::sqrt。如果这样做,将不会使用其他功能。
std::sqrt如果已知,为什么它不能推断出 的参数/返回类型?
与 C 版本不同sqrt,std::sqrt重载了
float sqrt ( float arg );
double sqrt ( double arg );
long double sqrt ( long double arg );
double sqrt ( IntegralType arg );
Run Code Online (Sandbox Code Playgroud)
并且编译器没有规则规定当您传递std::sqrt给std::transform. 为了解决这个问题,我们可以使用 lambda 将调用移动到sqrt编译器可以执行重载解析的上下文中。那看起来像
std::transform(a.begin(),
a.end(),
a.begin(),
[](auto val){ return std::sqrt(val); });
Run Code Online (Sandbox Code Playgroud)
std::sqrt现在需要您使用正确的版本。
| 归档时间: |
|
| 查看次数: |
103 次 |
| 最近记录: |