Подтвердить что ты не робот

Является ли std:: abs (0u) плохо сформированным?

Учитывая следующую программу:

#include <cmath>

int main()
{
    std::abs(0u) ;
}

gcc и clang не согласны с тем, является ли это плохо сформированным. Используя gcc с libstdc++, код строит без ошибок или предупреждений (видеть его в прямом эфире), используя clang с libc++ он генерирует следующую ошибку (видеть ее в прямом эфире):

error: call to 'abs' is ambiguous
std::abs(0u) ;
^~~~~~~~

Какой результат правильный? Должно ли abs(0u) быть двусмысленным или нет?


MSalters указывает на интересный вопрос: Шаблонная версия std:: abs.

4b9b3361

Ответ 1

Похоже, что libstdc++ верен, это не плохо сформировано, хотя мы увидим, что есть некоторые сомнения в том, является ли это дефектом в активной проблеме LWG 2192.

В стандартном разделе проекта С++ 11 26.8 [c.math] paragraph 11 говорится:

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

и включает в себя следующий элемент:

  1. В противном случае, если любой аргумент, соответствующий двойному параметру, имеет тип double или integer, то все аргументы, соответствующие двойные параметры эффективно дублируются.

и мы можем видеть, что это libstdc++ делает действительно для этого случая:

template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                                  double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }

Существует также отчет об ошибке gcc std:: abs (long long) относится к std:: abs (double), если llabs отсутствует, который задает вопрос, правильна ли эта реализация, и один ответ говорит:

[...] отлично подходит для стандарта, любое целое число должно безоговорочно становятся двойными. [...]

Отчет об ошибке в конечном итоге приведет к LWG active issue 2192: Недействительный и возвращаемый тип std:: abs (0u) нечетко говорит, среди прочего:

  • В С++ 11 дополнительное правило "достаточной перегрузки" с 26.8 [c.math] p11 (см. также LWG 2086) можно прочитать применительно к std:: abs() перегрузки также, что может привести к следующему Выводы:

Программа

    #include <type_traits>
    #include <cmath>

    static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops");

    int main() {
      std::abs(0u); // Calls std::abs(double)
    }

требуется быть хорошо сформированным из-за подпула 2 ( "[..] или целочисленный тип [..]" ) из 26.8 [c.math] p11 (Обратите внимание, что текущий разрешение LWG 2086 не устраняет эту проблему).

  1. Любая единица перевода, включающая оба и может быть плохо сформирована из-за двух противоречащих требованиям для типа возврата перегрузки std:: abs (int).

Мне кажется, что по крайней мере второй результат не предназначен, лично я думаю, что оба несчастны [...] Он также должен быть отметил, что соответствующее правило "общего типа функции" установлено из C99/C1x в 7.25 p2 + 3 ограничивается функциями с плавающей запятой от и, следовательно, нельзя применять к абс функции (но для функций fabs!).

Вопрос заключается в том, должно ли оно применяться к abs. Это может быть дефектом, поскольку не представляется возможным интерпретировать текущую формулировку, чтобы исключить abs.

Таким образом, текущая формулировка означает, что libstdc++ является совместимым, непонятно, почему libc++ выбрал свою текущую реализацию как есть. Я не могу найти никаких сообщений об ошибках или обсуждений, связанных с этой темой, и проблема LWG не говорит о расходящихся реализациях.

Предлагаемое решение сделало бы std::abs(0u) плохо сформированным:

Если abs() вызывается с аргументом неподписанного интегрального типа, не могут быть преобразованы в int путем цельной рекламы ([conv.prom]), программа плохо сформирована. [Примечание: аргументы, которые можно повысить до int разрешены для совместимости с C. - end note]

В то время как некоторые могут подвергнуть сомнению понятие использования abs с неподписанным типом, Говард Хиннант указывает в отчете, что при использовании шаблонов такие последствия могут быть не очевидными и приводят пример:

[...] особенно на С++, где у нас есть шаблоны, а также типы не всегда очевидны программисту во время разработки. Например, рассмотреть следующие вопросы:

template <class Int>
Int
analyze(Int x, Int y)
{
  // ...
  if (std::abs(x - y) < threshold)
  {
    // ...
  }
  // ...
}