Natknąłem się na takie zachowanie, std::gcd
które okazało się nieoczekiwane:
#include <iostream>
#include <numeric>
int main()
{
int a = -120;
unsigned b = 10;
//both a and b are representable in type C
using C = std::common_type<decltype(a), decltype(b)>::type;
C ca = std::abs(a);
C cb = b;
std::cout << a << ' ' << ca << '\n';
std::cout << b << ' ' << cb << '\n';
//first one should equal second one, but doesn't
std::cout << std::gcd(a, b) << std::endl;
std::cout << std::gcd(std::abs(a), b) << std::endl;
}
Uruchom w eksploratorze kompilatorów
Zgodnie z preferencją obu wywołań std::gcd
należy się poddać 10
, ponieważ wszystkie warunki wstępne są spełnione.
W szczególności wymagane jest jedynie, aby wartości bezwzględne obu operandów były reprezentowalne we wspólnym typie:
Jeśli albo | m | lub | n | nie jest reprezentowalna jako wartość typu
std::common_type_t<M, N>
, zachowanie jest niezdefiniowane.
Jednak pierwsze połączenie powraca 2
. Czy coś mi umyka? Zarówno gcc, jak i clang zachowują się w ten sposób.
-120 % 10u
? (Wskazówka: nie jest to 0.) Tak, błąd.
-120
do unsigned
spowoduje 4294967176
który % 10u
jest 6
. Moje pytanie dotyczyło raczej tego, czy takie zachowanie jest rzeczywiście nieprawidłowe, a wydaje się, że tak.
unsigned
, więc też nie będzie żadnego błędu