以下代码编译并生成对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
我想知道为什么编译器不会产生至少一个警告。
答案 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
。