如何使用 std::sqrt 作为 std::function?
这是代码:
#include <iostream>
#include <cmath>
#include <functional>
#include <complex>
int main() {
// This works.
std::function<float(float)> f = [](auto const& x) {return std::sqrt(x);};
// This also works. Why this works?!
using Complex = std::complex<double>;
std::function<Complex(const Complex&)> g = std::sqrt<double>;
// All of the following doesn't work.
// error: conversion from ‘<unresolved overloaded function type>’
// to non-scalar type ‘std::function<float(float)>’ requested
std::function<float(float)> a = std::sqrtf<float>;
std::function<float(float)> b = std::sqrt<float>;
std::function<float(float)> c = std::sqrt;
std::function<double(double)> d = std::sqrt<double>;
}
考虑到std::sqrt 参考,我真的很困惑为什么一个涉及复杂的工作,为什么其他的不起作用。
我知道这个问题,但是,我对使用std::complex,不感兴趣,并且,这个问题中的 OP 特别要求std::complex,相反,我只想使用floator double(或真正有价值的,不复杂)。
这是怎么回事?这样做的正确方法是什么?
回答
的浮点重载std::sqrt()和std::sqrtf()没有模板,所以这些形式都是无效的语法:
std::function<float(float)> a = std::sqrtf<float>;
// and
std::function<double(double)> d = std::sqrt<double>;
这种形式:
std::function<float(float)> c = std::sqrt;
没问题,除了std::sqrt()重载之外,因此名称不能像未重载时那样衰减为单个指针。
为了消除使用哪个重载的歧义,您需要将函数强制转换为正确的类型:
std::function<float(float)> works = static_cast<float(*)(float)>(std::sqrt);
但是正如您所看到的,语法有点冗长,这就是为什么 lambda 版本是执行此操作的首选方式。
此表格有效的原因:
std::function<Complex(const Complex&)> g = std::sqrt<double>;
是因为std::complex版本std::sqrt()是模板,其中模板参数是复杂对象的底层类型。
您看错了std::sqrt页面:它是非模板版本的页面。
如果您使用std::sqrt<double>和std::sqrt<float>函数,则您使用的是本页中引用的的模板版本。std::sqtr
如你看到的, std::sqrt<T>
template< class T >
complex<T> sqrt( const complex<T>& z );
接收 astd::complex<T>并返回 a std::complex<T>。
所以当你写
std::function<float(float)> f = [](auto const& x) {return std::sqrt(x);};
之所以有效std::sqrt(x),x是因为 lambda 调用 ( , where is a float) 不是模板函数。
当你写
std::function<Complex(const Complex&)> g = std::sqrt<double>;
有效是因为std::sqrt<double>它的模板版本std::sqrt接收一个Complex const &( std::complex<double> const &) 并返回一个Complex const &
但是当你写一些东西时
std::function<float(float)> b = std::sqrt<float>;
std::function<double(double)> d = std::sqrt<double>;
您通过函数接收和返回一个复杂的std::function等待函数接收并返回一个简单(不复杂)的浮点类型。
为了使其工作,您必须使用std::sqrt(所以 no<float>和 no <double>)的非模板版本并转换正确的指针类型(以选择std::sqrt非模板但重载版本的正确版本)。这也适用于c.
std::function<float(float)> b = (float(*)(float))std::sqrt;
std::function<float(float)> c = (float(*)(float))std::sqrt;
std::function<double(double)> d = (double(*)(double))std::sqrt;
对于a问题
std::function<float(float)> a = std::sqrtf<float>;
是不同的; 您必须删除模板部分 ( <float>),因为它std::sqrtf不是模板函数。
所以应该有效(std::sqrtf没有超载,所以不需要演员表,因为没有歧义)
std::function<float(float)> a = std::sqrtf;
不幸的是,我发现这不适用于 clang++ 和 g++。据我了解,那是因为cmath没有把sqrtf里面std的命名空间(和我看来,g ++以及铛++不符合)。
所以(使用 g++ 和 clang++)有效
std::function<float(float)> a = sqrtf;