Неверное разрешение перегрузки для функций с двумя аргументами

Давайте возьмем следующий пример программы:

#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 это дает мне:

ошибка C2440: «преобразование»: невозможно преобразовать из «плавающего» в
‘Half_float :: половина’

Так что, похоже, разрешение перегрузки не выбирает версию из пространства имен half_float (что ADL должен выполнить), но один из std используя неявное преобразование в float, Но странно то, что это происходит только для atan2 звоните, а не sin вызов.

В более крупном проекте, где эта ошибка фактически впервые возникла у меня, она также возникает для других функций с двумя аргументами (или, скорее, с half аргументы), как fmod, но не для любой функции с 1 аргументом. Аналогично в более крупном проекте он также отлично работает для gcc 4.6 / 4.7 а также лязг 3.1 без ошибок, хотя я не тестировал эту версию SSCCE явно там.

Так что мой вопрос, это ошибочное поведение на VS 2012сторона (учитывая, что это происходит только для 2012 и только для функции с двумя аргументами), или я наблюдал за некоторыми тонкостями в правилах разрешения перегрузки (которые могут быть немного хитрыми, я думаю)?

РЕДАКТИРОВАТЬ: Также бывает, если я напрямую using namespace half_float или поместите все это в глобальное пространство имен напрямую. Точно так же это происходит, если я не using namespace std, но это скорее VS-реализация, помещающая математические функции в глобальное пространство имен.

РЕДАКТИРОВАТЬ: Бывает как с оригиналом ВК 2012 компилятор, а также Ноябрь 2012 ОСАГО этого

РЕДАКТИРОВАТЬ: Хотя я не совсем уверен, что это действительно нарушение стандарта в самом строгом смысле, я подал ошибка поскольку он основан на выводах из моего ответа, поскольку он по меньшей мере не соответствует определению функций с 1 аргументом и заслуживает дальнейшего изучения В.С.-Команда.

9

Решение

Я думаю, что нашел причину. Стандарт C ++ говорит в разделе 26,8 [c.math], что для математических функций библиотеки C,

должны быть дополнительные перегрузки, достаточные для обеспечения:

  1. Если какой-либо аргумент, соответствующий параметру double, имеет тип long double, то все аргументы, соответствующие параметрам double,
    эффективно разыграть в длинный дубль.
  2. В противном случае, если какой-либо аргумент, соответствующий параметру double, имеет тип double или целочисленный тип, то все аргументы, соответствующие
    Двойные параметры эффективно приводятся к удвоению.
  3. В противном случае все аргументы, соответствующие двойным параметрам, эффективно приводятся к плавающей точке.

Что также можно увидеть в документация atan2.

Эти перегрузки предоставляются VS 2012 с помощью шаблона общей функции в форме:

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

Таким образом, у нас есть шаблонная функция, создание которой будет включать неявное преобразование (из half& в const half_expr<half>&) и шаблонную функцию, которую можно создать напрямую. Таким образом, последний является предпочтительным. Этого не происходит для функций с 1 аргументом, потому что для них должна быть только общая версия для целочисленных аргументов, которая предоставляется VS 2012 только для тех, кто использует std::enable_if из std::is_integral,

Но я думаю, что стандарт немного неясен в отношении того факта, что «дополнительные перегрузки» должны быть предоставлены только для встроенных типов. Так что, в конце концов, я все еще не уверен, если VS 2012 строго нарушает стандарт с его чрезмерно общими функциями или если это жизнеспособный вариант реализации, чтобы обеспечить их.

РЕДАКТИРОВАТЬ: Как кажется, уже есть отчет о дефектах 2086 поскольку стандартная неясная формулировка и исправление находятся в процессе, ограничение требования для этих дополнительных перегрузок только арифметическими типами. Поскольку это, кажется, всегда было первоначальным намерением (и реализовано почти всеми существующими реализациями), и это была просто неясная формулировка, я действительно считаю это ошибкой в VS 2012Реализация.

6

Другие решения

Я только что попробовал твой код и понял, что с ним не так.

Так как вы не реализовали half::sin а также half::atan2, компоновщик все равно выдаст ошибку. Так что если вы реализуете методы half::sin а также half::atan2, это должно решить ее (я реализовал их, позволив им вернуть пустую половину, что, конечно, бессмысленно).

После того, как я сделал этот шаг (предоставив (бессмысленную) реализацию двух обязательных методов), сообщения об ошибках почти волшебным образом исчезли.

Может быть, это не решение вашей проблемы, так как я использую GCC, а не VS.


РЕДАКТИРОВАТЬ: Я только что попробовал пример, который я использовал с G ++ с Visual Studio, который дал мне сообщение об ошибке peculier. При условии странности ошибки и кода, работающего с GCC, я должен сделать вывод, что это ошибка в VC2012.

0

Обходной путь должен специализироваться _Common_float_type за half а также half_expr быть неопределенным типом, так что SFINAE избавится от версии VS2012 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>;
}

Обратите внимание, что вы должны специализироваться для всех четырех комбинаций half а также half_exprпотому что специализация шаблона не учитывает базовые классы.

0
По вопросам рекламы [email protected]