为什么这个对isnan的调用不含糊? a.k.a.关键字使用引入2次类似的函数声明

时间:2017-01-03 12:15:01

标签: c++ namespaces

以下代码编译并生成对std::isnan的调用,请参阅here

#include <iostream>
#include <cmath>

namespace foo {
    template<class T> 
    inline bool isnan (T x)
    { //Fake function returning always true
       std::cout << "foo::isnan" << std::endl;
       return true;
    }
}

using foo::isnan;
using std::isnan;

int main () {
    std::cout << isnan(5.5f) << std::endl;
    return 0;
}

为什么这个函数调用不明确?

看看cmath.h,我看到了:

  template<typename _Tp>
    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
                       int>::__type
    isnan(_Tp __f)
    {
      typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
      return __builtin_isnan(__type(__f));
    }

,至少对我来说,看起来不一定是更好的匹配。

这个问题的动机:

我找到了这些代码行(可能是某些Eclipse自动生成的结果)

using std::isnan
using boost::math::isnan

我想知道为什么编译器不会产生至少一个警告。

1 个答案:

答案 0 :(得分:5)

当您#include <cmath>时,实现必须声明以下重载,或者表现为声明了这些重载:

bool isnan( float arg );
bool isnan( double arg );
bool isnan( long double arg );
bool isnan( Integral arg );

其中第一个是最好的匹配,所以编译器必须选择它。 (对于那些关心的人,N4141中的相关标准为26.8 / 10。)

请注意,最后一次重载可能会以与您的模板冲突的方式声明,在这种情况下using std::isnan;将导致重新声明错误。 (这发生在gcc5及更早版本中。)如果using不会导致错误,那么调用就会很好。

有趣的是,clang确实认为这个电话含糊不清。这不应该像我上面解释的那样发生。

  

我想知道编译器为什么不会产生至少一个警告。

您正在使用using功能将声明拉入某个范围,这是预期用途。所以我认为没有理由在这里发出警告。但是,我会以这样的方式配置我的编辑器,这样就不会自动生成using这样的声明,因为这可能会产生令人惊讶的结果。

在我上面粘贴的字面意义上不应理解这种重载。确切地说,重载代表的是实现定义,它可能是一组重载,一个模板,......它的行为类似于将所有整数类型的参数强制转换为double