Re: Explicit typedef
On May 7, 8:33 pm, jlongstr...@gmail.com wrote:
Please correct any misconceptions, or voice concerns about this being
a stupid idea in general.
I was wondering today: why doesn't C++ have explicit typedefs?
explicit typedef unsigned int ScreenXCoord;
explicit typedef unsigned int ScreenYCoord;
explicit typedef unsigned int WindowXCoord;
explicit typedef unsigned int WindowYCoord;
ScreenXCoord sx1, sx2;
ScreenYCoord sy1, sy2;
WindowXCoord wx1, wx2;
WindowYCoord wy1, wy2;
...
sx1 = sx2; // ok
sy1 = sy2; // ok
wx1 = wx2; // ok
wy1 = wy2; // ok
sx1 = wy1; // error, converting WindowYCoord to ScreenXCoord
This way, ScreenXCoord != ScreenYCoord != WindowXCoord !=
WindowYCoord.
Many times, it can be unclear what sort of thing a particular value
refers to, even knowing its type, especially with integers, which
could mean width, height, count of bytes, inches, days in a payroll
period, or just about anything else. This is why Hungarian notation
was invented -- cbCount is count of bytes, wxWidth is width in window
coordinates, etc.
Obviously, typedefs are one part of the solution -- it's obvious what
a variable declared as ScreenXCoord is for. But there's no stopping
the programmer from assigning a non-typedef'd unsigned int or another
typedef of unsigned int to that variable.
It seems to me the solution would be to add support for the explicit
keyword to typedef. It would be something like enum in C++,
convertible from their underlying type in some cases, but not the
others.
Once again, please post any criticism (or praise, if I really haven't
overlooked anything).
C++ has classes, and in this case, what *are) you dealing with?
axis values or coordinates?
Think encapsulation.
Generate a coordinate point, move it to a specific location.
Generate a Screen Coord there, move the original point again, generate
a Window coordinate there.
A window coordinate can be created from a screen coordinate but not
vice-versa.
#include <iostream>
template< typename T = unsigned >
class Coord
{
T x;
T y;
public:
// def parametized ctor
Coord(const T x_ = T(), const T y_ = T())
: x(x_), y(y_) { }
// compiler defined copy ctor will do
// virtual dtor required if you plan to use Coord* ptrs
T getX() const { return x; }
T getY() const { return y; }
void move(const T x_, const T y_)
{
x += x_;
y += y_;
}
protected:
void set(const T x_, const T y_)
{
x = x_;
y = y_;
}
friend std::ostream&
operator<<(std::ostream& os, const Coord& r_c)
{
os << "x = " << r_c.x;
os << "\ty = " << r_c.y;
return os;
}
};
template< typename T = unsigned >
class ScreenCoord : public Coord< T >
{
public:
explicit ScreenCoord(const Coord< T >& c)
: Coord< T >(c) { }
};
template< typename T = unsigned >
class WindowCoord : public Coord< T >
{
public:
explicit WindowCoord(const Coord< T >& c)
: Coord< T >(c) { }
// conversion op=
WindowCoord& operator=(const ScreenCoord< T > rhv)
{
set(rhv.getX(), rhv.getY());
return *this;
}
};
typedef Coord< > u_coord;
typedef ScreenCoord< > u_screencoord;
typedef WindowCoord< > u_windowcoord;
int main()
{
u_coord point;
std::cout << "point: " << point << std::endl;
std::cout << "point.move(+10, +20)\n";
point.move(+10, +20);
u_screencoord sc( point );
std::cout << "screencoord: " << sc << std::endl;
std::cout << "point.move(+20, +5)\n";
point.move(+20, +5);
u_windowcoord wc( point );
std::cout << "windowcoord: " << wc << std::endl;
std::cout << "\nwindowcoord = screencoord\n";
wc = sc; // ok
std::cout << wc << std::endl;
// sc = wc; // error, no conv op= available
}
/*
point: x = 0 y = 0
point.move(+10, +20)
screencoord: x = 10 y = 20
point.move(+20, +5)
windowcoord: x = 30 y = 25
windowcoord = screencoord
x = 10 y = 20
*/
___
And if one day a client codes the following mistake:
u_coord pt;
u_coord another(pt.getY(), pt.getY());
suggest the natural alternative - copy ctor:
u_coors pt;
u_coord( pt );
And now you have a system, not just a few typedefs that don't mean
anthing.