2015-05-13 27 views
1

以下简化代码无法在VS2013编译:可能ADL错误2013

#include <cmath> 
namespace mine 
{ 
    template <typename A> 
    struct Base 
    { 
     double value() const { return static_cast<const A&>(*this).value(); } 
    }; 

    struct Derived : Base <Derived> 
    { 
     Derived(double x) : m_val(x) {} 
     double value() const { return m_val; } 
     double m_val; 
    }; 

    template <typename A> 
    bool isnan(const Base<A>& x) { return ::isnan(x.value()); } 

    struct ItWorks 
    { 
     double value() const { return 3.14; } 
    }; 
    bool isnan(ItWorks t) { return ::isnan(t.value()); } 
} 

int main() 
{ 
    mine::Derived d(2.0); 
    bool b = isnan(d); // this one fails in VS2013 

    mine::ItWorks t; 
    bool bb = isnan(t); // this one works 

    return 0; 
} 

的错误是:

c:\program files (x86)\microsoft visual studio 12.0\vc\include\math.h(425): error C2665: 'fpclassify' : none of the 3 overloads could convert all the argument types 
could be 'int fpclassify(long double)' 
or  'int fpclassify(double)' 
or  'int fpclassify(float)' 
while trying to match the argument list '(mine::Derived)' 

我期待那ADL会踢打电话​​时在mine::Derived上调用,但由于某种原因,VS2013正试图从全局命名空间调用isnan()模板函数。

当然,如果我叫​​直接一切正常,但因为我需要调用isnan()在模板方面,我可能会得到一个doublemine::CRTP派生的任何类,这并不解决我的问题。使用CRTP一个简单的结构

它必须与模板扣除一定的相互作用,因为一切都按预期mine::ItWorks

但是,gcc 5.1.0和clang 3.5.1都认同我并正确地编译了代码。这看起来像一个VS2013的bug ...

任何想法? 谢谢!

+0

它*必须*是与模板演绎相关的东西,因为如果我在名称空间'mine'中添加一个重载'bool isnan(const Derived&x)',那么一切都可以工作。 – dats

+0

为了清楚起见,为* every *函数和* from'mine :: CRTP'派生的每个*类添加重载是*不是一个可行的解决方案,因为有许多函数和许多派生类... :( – dats

回答

2

它似乎不是我所看到的一个错误。

template<class _Ty> inline __nothrow bool isnan(_Ty _X) 

template<typename A> bool isnan(const Base<A>& x) 

isnan被赋予一个Derived类型它将明确使用派生函数定义匹配,这些功能将分别解析为

bool isnan(Derived _X) 

bool isnan(const Base<Derived>& x) 

因此,。并且由于fpclassify无法处理Derived而发生错误。

而不是尝试覆盖isnan具有模板变量类型,请覆盖fpclassify函数。

template <typename A> 
int fpclassify(const Base<A>& x) 
{ 
    return ::fpclassify(x.value()); 
} 

然后您的实施将工作。

从评论

isnan更新可能会在全局命名空间(从文件math.h),而不是仅仅在STD(CMATH)这将导致冲突。 - Source

+0

I刚刚发现[这里](http://stackoverflow.com/questions/18128899/is-isnan-in-the-std-namespace-more-in-general-when-is-std-necessary-optio)“一个实现允许进入全局命名空间“我一直认为isnan是在命名空间std中,现在你的回答是有道理的,如果你明确地表明了这一点(isnan可能在全局命名空间中)我会接受你的答案。 – dats