Movatterモバイル変換


[0]ホーム

URL:



This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++17 status.

2735.std::abs(short),std::abs(signed char) and others should returnint instead ofdouble in order to be compatible with C++98 and C

Section: 29.7[c.math]Status:C++17Submitter: Jörn HeusippOpened: 2016-06-16Last modified: 2017-07-30

Priority:3

View all otherissues in [c.math].

View all issues withC++17 status.

Discussion:

Consider this C++98 program:

#include <cmath>#include <cstdlib>int main() {  return std::abs(static_cast<short>(23)) % 42;}

This works fine with C++98 compilers. At thestd::abs(short) call, short gets promoted toint andstd::abs(int) is called.

C++11 added thefollowing wordingon page 1083 §26.9 p15 b2 [c.math]:

Otherwise, if any argument of arithmetic type corresponding to adouble parameter has typedouble or an integer type, then all arguments of arithmetic type corresponding todouble parameters are effectively cast todouble.

C++17 draftadditionally adds onpage 1080 §26.9 p10 [c.math]:

Ifabs() is called with an argument of typeX for whichis_unsigned<X>::value istrue and ifX cannot be converted toint by integral promotion (4.5), the program is ill-formed. [Note: Arguments that can be promoted toint are permitted for compatibility with C. —end note]

It is somewhat confusing and probably even contradictory to on the one hand specifyabs() in terms of integral promotion in §26.9 p10 and on the other hand demand all integral types to be converted todouble in §26.9 p15 b2.

Most compilers (each with their own respective library implementation) I tested (MSVC, Clang, older GCC) appear to not consider §26.9 p15 b2 forstd::abs and compile the code successfully. GCC 4.5-5.3 (forstd::abs but not for::abs) as well as GCC >=6.0 (for bothstd::abs and::abs) fail to compile in the following way: Taking §26.9 p15 b2 literally and applying it toabs() (which is listed in §26.9 p12) results inabs(short) returningdouble, and withoperator% not being specified fordouble, this makes the programm ill-formed.

I do acknowledge the reason for the wording and semantics demanded by §26.9 p15 b2, i.e. being able to call math functions with integral types or with partly floating point types and partly integral types. Converting integral types todoublecertainly makes sense here for all the other floating point math functions.However,abs() is special.abs() has overloads for the 3 wider integral types which return integral types.abs() originates in the C standard instdlib.h and had originally been specified for integral types only. Calling it in C with a short argument returns anint. Callingstd::abs(short) in C++98 also returns anint. Callingstd::abs(short) in C++11 and later with §26.9 p15 b2 applied toabs() suddenly returns adouble.

Additionally, this behaviour also breaks third-party C headers which contain macros or inline functions callingabs(short).

As per discussion on std-discussion, my reading of the standard as well as GCC's interpretation seem valid.However, as can be seen, this breaks existing code.

In addition to the compatibilty concerns, havingstd::abs(short) returndouble is also very confusing and unintuitive.

The other (possibly, depending on their respective size relative toint) affected types besidesshort aresigned char,unsigned char andunsigned short, and alsochar,char16_t,char32_t andwchar_t, (all of these are or may be promotable toint). Wider integral types are not affected because explicit overloads are specified for those types by §26.9 p6, §26.9 p7 and §26.9 p9.div() is also not affected because it is neither listed in §26.9 p12, nor does it actually provide any overload fordouble at all.

As far as I can see, the proposed or implemented solutions for LWG2294(i),2192(i) and/or2086(i) do not resolve this issue.

I think both, §26.9 p10 [c.math] and §26.9 p15 [c.math] need some correction and clarification.

(Note: These changes would explicitly render the current implementation in GCC's libstdc++ non-conforming, which would be a good thing, as outlined above.)

Previous resolution [SUPERSEDED]:

This wording is relative to N4594.

  1. Modify 29.7[c.math] as indicated:

    -10- Ifabs() is called with an argument of typeX for whichis_unsigned<X>::value istrue and ifX cannot be converted toint by integral promotion (4.5), the program is ill-formed.Ifabs() is called with an argument of typeX which can be converted toint by integral promotion (4.5), the argument is promoted toint. [Note: Arguments that can be promoted toint arepromoted toint in order to keeppermitted for compatibility with C. —end note]

    […]

    -15- Moreover, there shall be additional overloadsfor these functions, with the exception ofabs(), sufficient to ensure:

    1. If any argument of arithmetic type corresponding to adouble parameter has typelong double, thenall arguments of arithmetic type (3.9.1) corresponding todouble parameters are effectively cast tolong double.

    2. Otherwise, if any argument of arithmetic type corresponding to adouble parameter has typedoubleor an integer type, then all arguments of arithmetic type corresponding todouble parameters areeffectively cast todouble.

    3. Otherwise, all arguments of arithmetic type corresponding todouble parameters have typefloat.

    See also: ISO C 7.5, 7.10.2, 7.10.6.

    [Note:abs() is exempted from these rules in order to stay compatible with C. —end note]

[2016-07 Chicago]

Monday: Some of this has been changed in N4606; the rest of the changes may be editorial.

Fri PM: Move to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

  1. Modify 29.7.1[cmath.syn] as indicated:

    -2- For each set of overloaded functions within<cmath>,with the exception ofabs, there shall be additionaloverloads sufficient to ensure:

    1. If any argument of arithmetic type corresponding to adouble parameter has typelong double, thenall arguments of arithmetic type (3.9.1) corresponding todouble parameters are effectively cast tolong double.

    2. Otherwise, if any argument of arithmetic type corresponding to adouble parameter has typedoubleor an integer type, then all arguments of arithmetic type corresponding todouble parameters areeffectively cast todouble.

    3. Otherwise, all arguments of arithmetic type corresponding todouble parameters have typefloat.

    [Note:abs is exempted from these rules in order to stay compatible with C. —end note]

    See also: ISO C 7.5, 7.10.2, 7.10.6.


[8]ページ先頭

©2009-2026 Movatter.jp