如何使用 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;

以上是如何使用 std::sqrt 作为 std::function?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>