0

我有一个复数类,我正在尝试实现一个函数来计算模数(这需要使用 sqrt)。

我的头文件如下:

#ifndef MY_CLASS_H
#define MY_CLASS_H

template <class T> class complex
{
    // function to overload operator<< a friend
    template <class T>
    friend std::ostream& operator<< (std::ostream &os, const complex<T> &z);
private:
    T re,im;
public:

    // Constructors & destructor
    complex(){re=im=0;}
    complex( const T& r, const T& i ) : re(r), im(i) {}
    ~complex(){}

    // Return real component
    T realcomp() const {return re;}
    // Return imaginary component
    T imagcomp() const {return im;}
    // Return modulus
    double modulus() {return sqrt(im*im + re*re);}

etc....

编译器输出错误:

error C2668: 'sqrt' : ambiguous call to overloaded function
 could be 'long double sqrt(long double)'
 or       'float sqrt(float)'
 or       'double sqrt(double)'

我知道这告诉我sqrt需要知道它通过它传递的数据类型。

对于我的程序,imre采用doubleorint值。

我说 sqrt 只会采用浮动值是对的吗?如果是这样,我如何在没有“数据丢失”警告的情况下强制 im 和 re 到浮点数。我可以在不转换它们的情况下做到这一点吗?

4

6 回答 6

2

不, sqrt 通常不采用浮点数。它需要什么取决于你的图书馆。在您的情况下,您有几个重载的 sqrt 函数,一个 take float,一个 takedouble和一个 take long double

您遇到的问题是它们都没有 take int,并且从 int 到您可以使用的类型有多次转换,因此编译器让您选择(通过强制转换)。如果您只使用doubleor int,则强制转换为double-- 不会损失 presision。如果您想long double在某个时候使用,请投射到那个位置。

double modulus() {return sqrt((double)im*im + re*re);}
于 2012-04-13T17:29:35.607 回答
1

有几种解决方案,但首先,您的代码存在问题:函数sqrt来自哪里。如果用户包括 <sqrt.h>,那么您应该只获得double版本,并且没有歧义。如果用户包含<csqrt>,那么在 C++11 之前,代码应该找不到任何sqrt; 在实践中,没有编译器正确地实现了这一点,你得到的取决于实现。

最安全的解决方案是声明一个你自己的特殊命名空间,包括<csqrt>,在其中定义sqrt你需要的,std::sqrt 在它们的实现中使用,然后sqrt在你的命名空间中调用:

#include <csqrt>

namespace SafetyFirst
{
    inline int
    sqrt( int in )
    {
        return static_cast<int>( std::sqrt( static_cast<double>( in ) ) );
    }

    inline double
    sqrt( double in )
    {
        return std::sqrt( in ) ;
    }

    //  And so on for any other types you might need.  The
    //  standard provides std::sqrt for the floating point
    //  types only.
}

这样,重载解析总是会找到一个完全匹配的,并且您可以准确地确定您真正想要的功能。而且您有一种方法让客户端定义可能可用的新数字类型:他们只需sqrt在相同的命名空间中定义它们,可能会转发到与类型相同的命名空间中的实现。

或者,您可以执行以下操作:

#include <cmath>    // To ensure getting a fixed set of overloads
using std::sqrt;

inline int
sqrt( int in )
{
    return static_cast<int>( std::sqrt( static_cast<double>( in ) ) );
}

//  And so on for any standard integral types you want...
//  And your class here...

对于客户端定义的类型,ADL 将确保编译器在正确的命名空间中查找,因此它们不必在您的命名空间中提供转发功能。

这实际上是一个相当不错的解决方案,除了它可能会搞砸不希望std::sqrt( float )在全局命名空间中找到的客户端代码。(这样的代码不可移植,但它可以存在于某些平台上。)

于 2012-04-13T17:45:22.173 回答
0

尝试这个:

double modulus() {return sqrt((double)im*im + re*re);}

您将始终double sqrt(double)以这种方式调用,但是根据您的描述,这可能没问题。

于 2012-04-13T17:23:31.983 回答
0

该问题是由 sqrt 的函数调用的模糊输入引起的。sqrt 函数有不同的输入参数(重载函数)浮点或双精度。

我有非常相似的问题:在我写的第一个代码中:

    #include <iostream>     // std::cout
    #include <cmath>    // std::sqrt

   int main()
    {
      float ss;
      ss= std::sqrt(120);  //in this line compiler not sure 120 is float or double
      std::cout<<ss;
      std::cin>>ss;
      return 0;
    } 

在这段代码中,编译器不确定参数是 float 还是 double

我们可以修复代码以确保参数的类型是浮点型还是双精度型,如下所示:

    #include <iostream>     // std::cout
    #include <cmath>    // std::sqrt

    int main()
    {
      float ss;  //you can change to double 
      ss=120;    //this line make compiler sure 120 is float 
      ss=std::sqrt(ss); //in this line compiler sure that sqrt function 
      std::cin>>ss;
      return 0;
    }
于 2013-08-14T07:59:42.497 回答
0

这里可能有点晚了,但我从模板中得到了帮助,帮助编译器选择了正确的函数。

#ifndef SQUARE_ROOT_HPP
#define SQUARE_ROOT_HPP

#include <cmath>

template<typename Scalar>
Scalar square_root(Scalar value)
{
    return square_root(static_cast<double>(value));
}

template<>
float square_root(float value)
{
    return std::sqrt(value);
}

template<>
double square_root(double value)
{
    return std::sqrt(value);
}

template<>
long double square_root(long double value)
{
    return std::sqrt(value);
}

#endif // SQUARE_ROOT_HPP
于 2017-01-04T07:23:02.997 回答
0

我的问题是类似的:我正在扩展我的旧资源以使其适合 mpreal 的额外使用 - 一项烦人的工作。最后一个问题:大模板中的一个小语句:

`T help = sqrt(g.eval(f.eval(a))());`

我不得不挣扎..无论我尝试什么都失败了——非常不同的错误消息,有些看起来很疯狂,比如从复杂的 sqrt 非法转换,但我只使用了浮点类型;将 mpreal 转换为 long double 丢弃精度。 if(std::is_floating_point<T>::value) .. 并且if(std::is_same<T,long double>::value) ..给出了误导性的错误消息,特别是当 T 是 long double 时,在 then-各自的 else-part 中使用 std:: 和 mpfr:: 会导致 then- 或 else-part 中不可解析的类型错误,具体取决于 T。

我会在这里找到一个解决方案 - 如果我只知道我的问题的根源......

我的解决方案:

inline long double wurz(long double x) { return std::sqrt(x); };
inline mpreal wurz(mpreal x) { return sqrt(x); };

template<class T>
  ....
  real_word helpa2 = wurz(g.eval(f.eval(a))());

当我想问时,我在这里找到了这个页面,是否有比我的更自然、更不愚蠢的解决方案..

于 2017-07-06T21:39:22.733 回答