首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在模板类中使用sqrt()函数时消除歧义

在模板类中使用sqrt()函数时消除歧义
EN

Stack Overflow用户
提问于 2012-04-14 01:14:43
回答 6查看 4.4K关注 0票数 0

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

我的头文件如下:

代码语言:javascript
复制
#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....

编译器输出错误:

代码语言:javascript
复制
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将接受doubleint的值。

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

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-04-14 01:29:36

不,sqrt通常不接受浮点数。它需要什么取决于你的库。在您的例子中,有几个重载的sqrt函数,一个接受float,一个接受double,另一个接受long double

问题是,它们都不接受int,而且有多个从int到您可以使用的类型的转换,所以编译器让您选择(通过强制转换)。如果您只使用doubleint,则强制转换为double --不会丢失准确性。如果你想在某一时刻使用long double,那就转换成那样。

代码语言:javascript
复制
double modulus() {return sqrt((double)im*im + re*re);}
票数 2
EN

Stack Overflow用户

发布于 2012-04-14 01:45:22

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

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

代码语言:javascript
复制
#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,可能会转发到与该类型位于相同名称空间中的实现。

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

代码语言:javascript
复制
#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 )。(这样的代码是不可移植的,但它可能存在于某些平台上。)

票数 1
EN

Stack Overflow用户

发布于 2012-04-14 01:23:32

试试这个:

代码语言:javascript
复制
double modulus() {return sqrt((double)im*im + re*re);}

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10145295

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档