Avatar von pre alpha
  • pre alpha

mehr als 1000 Beiträge seit 13.05.2006

hab noch was

Hallo Andreas,
hab in der i'X Deinen Beitrag gelesen und Rainer hatte darüber ja auch schon geschrieben. Zuerst der Code

struct QPoint { int x{}, y{}; }; struct point_int { int x{}, y{}; inline constexpr point_int() noexcept = default; inline constexpr point_int(const point_int&) noexcept = default; inline constexpr point_int(point_int&&) noexcept = default; inline constexpr point_int(const int _x, const int _y) noexcept : x{_x}, y{_y} {} inline constexpr point_int(const QPoint& q) noexcept : x{q.x}, y{q.y} {} // 1 inline constexpr auto operator<=>(const point_int&) const noexcept = default; //inline constexpr bool operator==(const point_int&) const noexcept = default; // 2 //inline constexpr auto operator<=>(const QPoint& q) const noexcept { return (*this) <=> point_int{q.x, q.y}; } // 3 //inline constexpr bool operator==(const QPoint& q) const noexcept { return (*this) == point_int{q.x, q.y}; } // 4 template <typename Char, typename Traits = std::char_traits<Char>> friend std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const point_int& arg) noexcept { stream << '(' << arg.x << ',' << arg.y << ')'; return stream; } }; template <typename Type> struct point { using value_type = Type; value_type x{}, y{}; inline constexpr point() noexcept = default; inline constexpr point(const point&) noexcept = default; inline constexpr point(point&&) noexcept = default; template <typename From> inline constexpr point(const point<From>& arg) noexcept : x{value_type(arg.x)}, y{value_type(arg.y)} {} template <typename X, typename Y> inline constexpr point(const X& _x, const Y& _y) noexcept : x{value_type(_x)}, y{value_type(_y)} {} inline constexpr auto operator<=>(const point&) const noexcept = default; inline constexpr bool operator==(const point&) const noexcept = default; /* template <typename Other> inline constexpr auto operator<=>(const point<Other>& arg) const noexcept { using compare_type = std::common_type_t<Type, Other>; return point<compare_type>{*this} <=> point<compare_type>{arg}; } template <typename Other> inline constexpr bool operator==(const point<Other>& arg) const noexcept { using compare_type = std::common_type_t<Type, Other>; return point<compare_type>{*this} == point<compare_type>{arg}; } */ template <typename Char, typename Traits = std::char_traits<Char>> friend std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const point& arg) noexcept { stream << '(' << arg.x << ',' << arg.y << ')'; return stream; } }; int main(const int argc, const char** args) { std::cout << std::boolalpha; if (argc == 3) { { const int a1=std::atoi(args[1]), a2=std::atoi(args[2]); const point_int a{a1, a2}, b{a1, a2}; const QPoint q{a1, a2}; std::cout << a << std::endl; std::cout << b << std::endl; std::cout<< (a==b) << std::endl; std::cout<< (b==a) << std::endl; std::cout<< (a==q) << std::endl; std::cout<< (q==a) << std::endl; } std::cout << std::endl; { const double a1=std::atof(args[1]), a2=std::atof(args[2]); const point<double> a{a1, a2}; const point<int> b{a1, a2}; std::cout << a << std::endl; std::cout << b << std::endl; std::cout<< (a==b) << std::endl; // 5 std::cout<< (b==a) << std::endl; // 6 } } return EXIT_SUCCESS; }

jetzt mein Senf.

In dem einfachen Fall point_int, also die Typen von QPoint und point_int sind gleich, kann man sich die Ausformulierung der Operatoren == und <=> sparen - Dein Listing 8. Da gibt es 2 Möglichkeiten:
- Man implementiert einen Konvertierungs-ctor für QPoint und kann sich dann sogar den ==-Op sparen (2), da das hier hinreichend (primitiv) ist.
- Möglicherweise ist aber nicht gewünscht den cvt-ctor zu haben. Also (1) raus und (2+3+4) rein. (3+4) konvertieren manuell QPoint nach point_int und rufen die default-Ops auf. (2+4) müssen in diesem Fall aber vorhanden sein, sonst gibts 'n Compilerfehler.

Nun wird ja heutzutage kein vernünftiger Mensch mehr sowas mit festen Typen implementieren - also 'n Template. Doch dann gibst ne kleine Überaschung. Der Aufruf

./Test 1 1

liefert das richtige Ergebniss

(1,1) (1,1) true true true true (1,1) (1,1) true true

jedoch

./Test 1 1000000000000000000

hingegen

(1,-1486618624) (1,-1486618624) true true true true (1,1e+18) (1,-2147483648) false true

Was ist passiert? Klar, in (5+6) wird einmal point<int> nach point<double> konvertiert und dann verglichen und einmal anders herum: point<double> nach point<int> und dies verglichen. Durch den Überlauf von int sind das natürlich 2 verschiedene Werte. Indem man die beiden auskommentierten Ops aktiviert, kann man dieses ungewünschte Verhalten abstellen, da dann immer gleiche Typen verglichen werden - alles natürlich nur im Rahmen der Genauigkeit bei den Konvertierungen:

(1,-1486618624) (1,-1486618624) true true true true (1,1e+18) (1,-2147483648) false false

cu
pre alpha

Das Posting wurde vom Benutzer editiert (26.02.2021 15:48).

Bewerten
- +