Incorrect overload resolution for 2-argument functions

前端 未结 3 380
粉色の甜心
粉色の甜心 2021-01-12 02:30

Let\'s take the following example program:

#include 

namespace half_float
{
    template struct half_expr {};

    struct hal         


        
相关标签:
3条回答
  • 2021-01-12 03:11

    I just tried your code, and I figured out what was wrong with it.

    Since you haven't implemented half::sin and half::atan2, the linker will throw an error anyway. So if you implement the methods half::sin and half::atan2, that should solve it (I implemented them by letting them return an empty half, which is, of course, meaningless).

    After I took that step (providing a (meaningless) implementation of the two required methods), the error messages almost magically disappeared.

    Maybe this isn't the solution to your problem, as I'm using GCC, and not VS.


    EDIT: I just tried the sample I used with G++ with visual studio, which gave me a peculier error message. Provided the strangeness of the error, and the code working with GCC, I must conclude that this is a bug in VC2012.

    0 讨论(0)
  • 2021-01-12 03:12

    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. If any argument corresponding to a double parameter has type long double, then all arguments corresponding to double parameters are effectively cast to long double.
    2. Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to double parameters are effectively cast to double.
    3. Otherwise, all arguments corresponding to double parameters are effectively cast to float.

    Which can also be seen in the atan2 documentation.

    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);
    

    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.

    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.

    EDIT: 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.

    0 讨论(0)
  • 2021-01-12 03:19

    A workaround is to specialise _Common_float_type for half and half_expr to be an undefined type, so that SFINAE gets rid of the VS2012 version of atan2.

    namespace std {
        template<class T1, class T2>
        struct _Common_float_type<half_float::half_expr<T1>, half_float::half_expr<T2>>;
        template<class T2>
        struct _Common_float_type<half_float::half, half_float::half_expr<T2>>;
        template<class T1>
        struct _Common_float_type<half_float::half_expr<T1>, half_float::half>;
        template<>
        struct _Common_float_type<half_float::half, half_float::half>;
    }
    

    Note that you have to specialise for all four combinations of half and half_expr, because template specialisation doesn't consider base classes.

    0 讨论(0)
提交回复
热议问题