Pregunta

I have a complex number class where I am trying to implement a function to work out the modulus (which requires the used of a sqrt).

My header file is as follows:

#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....

The compiler outputs the error:

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

which I know is telling me that the sqrt needs to know what type of data it is passing through it.

For my program, im and re will take either double or int values.

Am I right in saying sqrt will only take floating values? If so how do I force im and re to floating points without a 'loss of data' warning. Can I do this without converting them?

¿Fue útil?

Solución

No, sqrt generally does not take floats. What it takes depends a on your libraries. In your case, you have several overloaded sqrt functions, one takes float, one takes double, and one takes long double.

The problem you have, is none of them take int, and there are multiple conversions from int to a type that you could be used, so the compiler makes you choose (by casting). If you are only using double or int, then cast to double -- there will be no loss of presision. If you want to use long double at some point, cast to that.

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

Otros consejos

There are several solutions, but first, there is a problem with your code: where does the function sqrt come from. If the user includes <sqrt.h>, then you should get only the double version, and no ambiguities. If the user includes <csqrt>, then in pre C++11, the code shouldn't find any sqrt; in practice, no compiler implemented this correctly, and what you get depends on the implementation.

The safest solution is to declare a special namespace of your own, include <csqrt>, define the sqrt you need in it, using std::sqrt in their implementation, and call the sqrt in your namespace:

#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.
}

This way, overload resolution will always find an exact match, and you determine exactly which function you actually want. And you have a way for clients to define new numeric types which might be usable: they just have to define their sqrt in the same namespace, probably forwarding to an implementation in the same namespace as the type.

Alternatively, you can do:

#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...

For client defined types, ADL will ensure that the compiler looks in the correct namespace, so they don't have to provide a forwarding function in your namespace.

This is actually a fairly nice solution, except that it could screw up client code not expecting to find std::sqrt( float ) in the global namespace. (Such code isn't portable, but it could exist on some platforms.)

Try this:

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

You'll always invoke double sqrt(double) this way, but that's probably ok, given your description.

The problem is caused by ambigues input of the function call of sqrt. The sqrt function has different input parameter (overloaded function) either float or double.

I have quite similar problem : in the first code I wrote :

    #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;
    } 

in this code, compiler not sure the parameter is float or double

we can just fix the code just to make sure which type of the parameter is, either float or double as follow :

    #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;
    }

Maybe a bit late here, but I got an help from templates to help the compiler chose the right function.

#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

My problem was similar: I'm expanding my old source to make it fit for an additional use of mpreal - an annoying job. One of the last problems: a little statement in a big template:

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

I had to struggle .. whatever I tried was failing - very different error messages, some looking crazy, like illegal conversion from complex sqrt, but I used only float types; converting mpreal to long double throwing away precision. if(std::is_floating_point<T>::value) .. and if(std::is_same<T,long double>::value) .. were giving misleading error messages, especially when T was long double, using std:: and mpfr:: in then- respective else-part was leading to not resolvable type errors in then- or else-part depending on T.

I would have found a solution here - if I only had known the source of my problem ...

My solution:

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))());

I found this page here when I wanted to ask, if there's a more natural, less stupid solution than mine ..

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top