Ответ 1
Похоже, что libstdc++
верен, это не плохо сформировано, хотя мы увидим, что есть некоторые сомнения в том, является ли это дефектом в активной проблеме LWG 2192
.
В стандартном разделе проекта С++ 11 26.8
[c.math] paragraph 11
говорится:
Кроме того, должны быть дополнительные перегрузки, достаточные для обеспечения:
и включает в себя следующий элемент:
- В противном случае, если любой аргумент, соответствующий двойному параметру, имеет тип 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 не устраняет эту проблему).
- Любая единица перевода, включающая оба и может быть плохо сформирована из-за двух противоречащих требованиям для типа возврата перегрузки 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) { // ... } // ... }