2参数函数的重载分辨率不正确 [英] Incorrect overload resolution for 2-argument functions

查看:82
本文介绍了2参数函数的重载分辨率不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们看下面的示例程序:

Let's take the following example program:

#include <cmath>

namespace half_float
{
    template<typename T> struct half_expr {};

    struct half : half_expr<half>
    {
        operator float() const;
    };

    template<typename T> half sin(const half_expr<T>&);
    template<typename T> half atan2(const half_expr<T>&, const half_expr<T>&);
}

using namespace std;
using half_float::half;

int main()
{
    half a, b;
    half s = sin(a);
    half t = atan2(a, b);
}

VS 2010 中,这可以正常编译(暂时忽略明显的链接器错误).但是在 VS 2012 中,这给了我:

In VS 2010 this compiles just fine (ignore the obvious linker errors for now). But in VS 2012 this gives me:

错误C2440:转换":无法从浮动"转换为'half_float :: half'

error C2440: 'conversion' : cannot convert from 'float' to 'half_float::half'

因此,似乎重载解析不会从名称空间 half_float (ADL应该完成)中选择版本,而是从 std 中使用隐式转换为的版本.>浮动.但是奇怪的是,这仅发生在 atan2 调用中,而不是 sin 调用.

So it seems overload resolution doesn't pick the version from namespace half_float (which ADL should accomplish), but the one from std using the implicit conversion to float. But the strange thing is, that this only happens for the atan2 call and not the sin call.

在较大的项目中,这个错误实际上最先发生在我身上,其他2参数函数(或具有2个 half 参数的函数)也发生了此错误,例如 fmod ,但不适用于任何1参数函数.同样,在较大的项目中,它也可以很好地在 gcc 4.6/4.7 clang 3.1 中正常运行,尽管我没有在那里明确测试过此SSCCE版本.

In the larger project, where this error actually first occured to me it also occurs for other 2-argument functions (or rather those with 2 half arguments), like fmod, but not for any 1-argument function. Likewise in the larger project it also works fine for gcc 4.6/4.7 and clang 3.1 without error, though I didn't test this SSCCE version explicitly there.

所以我的问题是,这是 VS 2012 的错误行为(假设仅在 2012 且仅在2参数函数中发生),还是我监督了过载解析规则中的一些微妙之处(我想这确实有些棘手)?

So my question is, is this erroneous behaviour on VS 2012's side (given that it only happens for 2012 and only for the 2-argument function), or did I oversee some subtleties in the overload resolution rules (which can indeed get a bit tricky, I guess)?

编辑:如果我直接使用名称空间half_float 或将整个内容直接放在全局名称空间中,也会发生这种情况.同样,如果我不使用命名空间std ,也会发生这种情况,但这是VS实现,将数学函数放在全局命名空间中.

It also happens if I'm directly using namespace half_float or put the whole thing in global namespace directly. Likewise does it also happen if I'm not using namespace std, but this is rather the VS-implementation putting the math functions in global namespace.

编辑:使用原始的 VC 2012 编译器和其 2012年11月CTP 都会发生这种情况.

It happens both with the original VC 2012 compiler as well as the November 2012 CTP of it.

编辑:尽管我不能完全确定它确实在严格意义上违反了该标准,但我已经提交了

Although I'm not completely sure it is really a violation of the standard in the strictest sense, I have filed a bug for it based on the findings in my answer, since it is at least inconsistent to the definition of the 1-argument functions and deserves further investigation by the VS-Team.

推荐答案

我认为我找到了原因.C ++标准在 26.8 [c.math] 部分中指出,对于C库的数学功能,

I think I found the cause. The C++ standard says in section 26.8 [c.math], that for the mathematical functions of the C library,

应该有足够的额外过载来确保:

there shall be additional overloads sufficient to ensure:

  1. 如果对应于double参数的任何参数的类型为long double,则对应于double参数的所有参数为有效地转换为长双.
  2. 否则,如果与double参数相对应的任何参数的类型为double或整数类型,则与之相对应的所有参数double参数有效地转换为double.
  3. 否则,所有与double参数相对应的参数都将有效地转换为float.

atan2文档中也可以看到.

这些重载由 VS 2012 通过使用以下形式的通用功能模板提供:

Those overloads are provided by VS 2012 through the use of a general function template of the form:

template<typename T,typename U> common_float_type<T,U>::type atan2(T, U);

因此,我们有一个模板函数,其实例化将涉及隐式转换(从 half& const half_expr< half> ),并且模板函数可以是直接实例化.因此,后者是优选的.对于1-argument函数,这种情况不会发生,因为对于那些函数,只需要有一个用于积分参数的通用版本,这是 VS 2012 为仅使用 std:的用户提供的: std :: is_integral 的enable_if .

So we have a template function whose instantiation would involve an implicit conversion (from half& to const half_expr<half>&) and a template function which can be instantiated directly. Thus the latter is preferred. This doesn't happen for the 1-argument functions because for those there only has to be a general version for integral arguments, which is provided by VS 2012 for only those using a std::enable_if of std::is_integral.

但是我认为对于那些附加重载" 仅为内置类型提供的事实,标准还不清楚.因此,最后我仍然不确定 VS 2012 是否因其过分泛泛的功能而严格违反了该标准,或者提供这些功能是否是可行的实现选择.

But I think the standard is a bit unclear about the fact that those "additional overloads" are to be provided only for builtin types. So in the end I'm still not sure if VS 2012 strictly violates the standard with its overly generic functions or if it is a viable implementation option to provide those.

编辑:看来,已经有

As it seems, there is already defect report 2086 for the standard's unclear wording and a fix is on it's way, limiting the requirement for those additional overloads to only arithmetic types. Since this seems to have always been the original intent (and realized by nearly all existing implementations) and it was merely the wording that was unclear, I would indeed regard this a bug in VS 2012's implementation.

这篇关于2参数函数的重载分辨率不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆