TL;DR
В соответствии со стандартом допустимо передавать неарифметические типы в качестве аргументов cmath
функциям, но в отчете о дефекте 2068
утверждается, что первоначальное намерение состояло в том, что cmath
функции должны быть ограничены арифметическими типами, и представляется возможным использовать неарифметические аргументы в конечном итоге. -сформированный. Таким образом, хотя технически допустимое использование неарифметических типов в качестве аргументов кажется сомнительным в свете отчета о дефекте 2068
.
Подробнее
Заголовок cmath рассматривается в черновом стандартном разделе 26.8
[c. math] обеспечивает дополнительную перегрузку float и long double для каждой функции, определенной в math.h, который принимает аргумент double и, кроме того, параграф 11
обеспечивает достаточное количество перегрузок и говорит :
При этом должны быть предусмотрены дополнительные перегрузки, достаточные для обеспечения:
- Если какой-либо аргумент, соответствующий параметру double, имеет тип long double, то все аргументы, соответствующие параметрам double, эффективно преобразуются в тип long double.
- В противном случае, если какой-либо аргумент, соответствующий параметру double, имеет тип double или целочисленный тип, то все аргументы, соответствующие параметрам double, фактически преобразуются в тип double.
- В противном случае все аргументы, соответствующие параметрам типа double, фактически преобразуются в число с плавающей запятой.
Это похоже на C++11
В разделе C++11 26.8
[c.math] нет никаких ограничений, запрещающих неарифметические аргументы для cmath
функций. В каждом случае из вопроса у нас есть доступная перегрузка, которая принимает аргумент(ы) double, и их следует выбирать через разрешение перегрузки.
Отчет о дефекте 2086
Но для C++14 у нас есть отчет о дефекте 2086: слишком универсальная поддержка типов для математических функций., в котором утверждается, что первоначальная цель раздела 26.8
[c.math] состояла в том, чтобы ограничить cmath
функций допустимыми только для арифметических типов, что будет имитировать то, как они работали на C:
У меня сложилось впечатление, что этот набор правил, вероятно, является более общим, как предполагалось, я предполагаю, что он написан для имитации набора правил C99/C1x в 7.25 p2+3 способом "C++" [...] (обратите внимание, что ограничения C допустимый набор для типов, которые C++ описывает как арифметические типы, но см. ниже одно важное отличие) [...]
и говорит:
Мое текущее предложение по устранению этих проблем состоит в том, чтобы ограничить допустимые типы аргументов этих функций арифметическими типами.
и изменена формулировка раздела 26.8
параграфа 11
(выделено мной):
При этом должны быть предусмотрены дополнительные перегрузки, достаточные для обеспечения:
- Если какой-либо арифметический аргумент, соответствующий параметру double, имеет тип long double, то все арифметические аргументы, соответствующие параметрам типа double, фактически преобразуются в тип long double.
- В противном случае, если какой-либо арифметический аргумент, соответствующий параметру double, имеет тип double или целочисленный тип, то все арифметические аргументы, соответствующие параметрам типа double, эффективно преобразуются в тип double.
- В противном случае все арифметические аргументы, соответствующие параметрам типа double, фактически преобразуются в
эффективно приводятся к типу float.
Значит, это неверно в C++14?
Что ж, несмотря на намерение, технически это выглядит все еще действительным, как утверждается в этом комментарии из обсуждения в отчет об ошибке libc++: некорректная реализация isnan и подобных функций:
Это могло быть намерением, но я не вижу никакого способа прочитать формулировку стандарта таким образом. Из примера в комментарии №0:
std::isnan(A());
Здесь нет аргументов арифметического типа, поэтому ни один из пунктов 26.8/11 не применим. Набор перегрузок содержит «isnan(float)», «isnan(double)» и «isnan(long double)», и следует выбрать «isnan(float)».
Таким образом, переформулировка DR 2086
параграфа 11 не делает неправильным называть float, double и long double< /em> перегружает доступные в противном случае неарифметические аргументы.
Технически допустимо, но сомнительно в использовании
Таким образом, хотя стандарт C++11 и C++14 не ограничивает cmath
функций арифметическими аргументами, DR 2068
утверждает, что цель 26.8
параграфа 11
заключалась в том, чтобы ограничить cmath
функциями принимать только арифметические аргументы и, по-видимому, предназначалась для закрытия лазейки в C++. 14, но не предусматривал достаточно сильных ограничений.
Кажется сомнительным полагаться на функцию, которая может стать неправильной в будущей версии стандарта. Поскольку у нас есть различия в реализации, любой код, который полагается на передачу неарифметических аргументов функциям cmath
для этих случаев, является непереносимым и поэтому будет полезен только в ограниченных ситуациях. У нас есть альтернативное решение, которое заключается в явном приведении неарифметических типов к арифметическим типам, что позволяет обойти всю проблему, нам больше не нужно беспокоиться о неправильном формате кода, и он переносим:
std::isgreater( static_cast<double>(s) ,1.0)
^^^^^^^^^^^^^^^^^^^^^^
Как указывает Potatoswatter, использование унарного +
также является вариантом:
std::isgreater( +s ,1.0)
Обновить
Как Т.С. указывает в C++11, можно утверждать, что 26.8
абзац 11
маркер 3
применим, поскольку аргумент не является ни long double, double, ни целым числом, и поэтому аргументы тип S
должен быть сначала приведен к типу float. Обратите внимание, как указано в отчете о дефекте, gcc
никогда не реализовывал это, и, насколько мне известно, clang
тоже.
person
Shafik Yaghmour
schedule
10.06.2015