Visual Studio 2013 年可能存在 ADL 错误
Possible ADL bug in Visual Studio 2013
以下简化代码在VS2013下编译失败:
#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)'
我原以为在 mine::Derived
上调用时 ADL 会开始调用 mine::isnan()
,但出于某种原因 VS2013 正试图从全局调用 isnan()
模板函数命名空间。
当然,如果我直接调用 mine::isnan()
一切正常,但这并不能解决我的问题,因为我需要在模板化的上下文中调用 isnan()
,在那里我可能会得到 double
或来自 mine::CRTP
.
的任何 class
它必须与模板推导有一些交互,因为 mine::ItWorks
的一切都按预期工作:使用 CRTP 的简单结构 not。
然而,gcc 5.1.0 和 clang 3.5.1 都同意我的观点,并且正确编译了代码。这看起来像是一个 VS2013 错误...
有什么想法吗?
谢谢!
据我所见,这似乎不是错误。
template<class _Ty> inline __nothrow bool isnan(_Ty _X)
template<typename A> bool isnan(const Base<A>& x)
这些函数将分别解析为
bool isnan(Derived _X)
bool isnan(const Base<Derived>& x)
因此,当 isnan
被赋予 Derived
类型时,它将匹配显式使用 Derived 的函数定义。并且发生错误是因为 fpclassify
无法处理 Derived.
与其尝试覆盖具有模板变量类型的 isnan
,不如覆盖 fpclassify
函数。
template <typename A>
int fpclassify(const Base<A>& x)
{
return ::fpclassify(x.value());
}
那么您的实施将起作用。
根据评论更新
isnan
可能在全局命名空间中(来自 math.h),而不仅仅是在导致冲突的 std (cmath) 中。 - Source
以下简化代码在VS2013下编译失败:
#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)'
我原以为在 mine::Derived
上调用时 ADL 会开始调用 mine::isnan()
,但出于某种原因 VS2013 正试图从全局调用 isnan()
模板函数命名空间。
当然,如果我直接调用 mine::isnan()
一切正常,但这并不能解决我的问题,因为我需要在模板化的上下文中调用 isnan()
,在那里我可能会得到 double
或来自 mine::CRTP
.
它必须与模板推导有一些交互,因为 mine::ItWorks
的一切都按预期工作:使用 CRTP 的简单结构 not。
然而,gcc 5.1.0 和 clang 3.5.1 都同意我的观点,并且正确编译了代码。这看起来像是一个 VS2013 错误...
有什么想法吗? 谢谢!
据我所见,这似乎不是错误。
template<class _Ty> inline __nothrow bool isnan(_Ty _X)
template<typename A> bool isnan(const Base<A>& x)
这些函数将分别解析为
bool isnan(Derived _X)
bool isnan(const Base<Derived>& x)
因此,当 isnan
被赋予 Derived
类型时,它将匹配显式使用 Derived 的函数定义。并且发生错误是因为 fpclassify
无法处理 Derived.
与其尝试覆盖具有模板变量类型的 isnan
,不如覆盖 fpclassify
函数。
template <typename A>
int fpclassify(const Base<A>& x)
{
return ::fpclassify(x.value());
}
那么您的实施将起作用。
根据评论更新
isnan
可能在全局命名空间中(来自 math.h),而不仅仅是在导致冲突的 std (cmath) 中。 - Source