Topic: strong typedef template, macro


Author: Kevin Lynch <krlynch@bu.edu>
Date: 03 May 03 14:08:52 GMT
Raw View
Siemel Naran wrote:
>
> Is it possible to get rid off macros?  Would something like this work
>
> template <class T, const char * Name>
> class strong_typedef_class {
>    ...
> };

If I'm remembering correctly, there is an article in the March 2003
C/C++ Users Journal that addresses this issue using templates.  The
article isn't online at the CUJ website, but here is the blurb from the
TOC for that issue:

True typedefs

     Matthew Wilson
     A template wrapper that provides type uniqueness for otherwise
synonymous types.


The code is available for download from

ftp://ftp.cuj.com/pub/2003/cujmar2003.zip

--
-------------------------------------------------------------------------------
Kevin Lynch    voice: (617) 353-6025
Physics Department   Fax: (617) 353-9393
Boston University   office:  PRB-361
590 Commonwealth Ave.   e-mail:  krlynch@bu.edu
Boston, MA 02215 USA   http://budoe.bu.edu/~krlynch
-------------------------------------------------------------------------------


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]




Author: Derek Ross <dross@iders.ca>
Date: 03 May 03 14:09:20 GMT
Raw View
 >  What went wrong?

It got me thinking in great depth of what kinds of bugs it would
prevent, in relation to all the bugs that have caused me problems in the
past.  I don't really think that strong typedefs would have really
helped much in making bug-free software.  But then again, maybe that's
because I learned to live without them.

 > Is it possible to get rid off macros?  Would something like this work

I was worried that if I didn't automate the creation of the unique
classes, then a simple typo could lead to a multiple typedefs being the
same type, with no compiler warning.

Derek.

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]




Author: pavel_vozenilek@yahoo.co.uk (Pavel Vozenilek)
Date: 3 May 2003 20:45:44 -0400
Raw View
Derek Ross <dross@iders.ca> wrote in message news:<DDfsa.75199$ya.2427357@news1.calgary.shaw.ca>...
>
> It seems that every once in a while, someone mentions that
> C++ is missing a "strong typedef" facility.
>
[...]

I wrote something similar, called "safer value conversions". It is
available on Yahoo file section
(http://groups.yahoo.com/group/boost/files/quantity2/ - source +
coumentation).

Class quantity_base acts in similar way as your code. It is also
possible to define conversions between different user types and invoke
them automatically.

I'd used it for conversion between several types of pixel positions
and several coordinates in image file, where pixel rounding rules are
quite complex.

/Pavel
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Derek Ross <dross@iders.ca>
Date: 02 May 03 03:00:16 GMT
Raw View
Hello,

It seems that every once in a while, someone mentions that
C++ is missing a "strong typedef" facility.

This briefly-tested macro/template combination emulates
a simplified version of such a facility.  Maybe some of
you will find it interesting to play with.

I only tested it on an older compiler (g++ 2.96) so
hopefully it doesn't implode on the newer ones.

The funny thing is, after I played around with strong
typedefs for a while, they didn't seem as wonderful
as I originally thought they would be.  Maybe that's
why C++ didn't have them in the first place!

USAGE:
To create strong typedefs of "float" named
"velocity_t" and "distance_t", you would call

  STRONG_TYPEDEF(float, velocity_t);
  STRONG_TYPEDEF(float, distance_t);

The types "velocity_t" and "distance_t" will behave mostly
like floats, and will be initializable from floats, but
will not be interchangable. For example, the following
code will be legal:

  distance_t a=10;
  distance_t b=20;
  a += b;

But the following code will not:

  distance_t a=10;
  velocity_t b=20;
  a += b;

To convert between the two, you have to access the .value member
like so:

  distance_t a=10;
  velocity_t b=20;
  a += b.value;

Derek Ross

==== Source File ===============================
/*

Notes about the STRONG_TYPEDEF macro.

Usage:
  STRONG_TYPEDEF(original_type, name_of_typedef);

Example:
  STRONG_TYPEDEF(double, dollars_t);

STRONG_TYPEDEF creates a template type that is basically
a wrapper around a built-in type such as int or double.
Most of the operators are overloaded to operate on the
wrapped variable.

Casting to the original type is not automatic.
To get to the wrapped variable, access the ".value"
member.

STRONG_TYPEDEF cannot be used to define a typedef
within a function, only globally.

This was tested with g++ 2.96.

*/

#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
#include <string>
#include <cmath>

#define MAKE_STRONG_TYPEDEF_OP_CONST(rettype, op)\
     rettype operator op \
     (const strong_typedef_class<T,Unique_T>& r) \
     const\
     {\
         return rettype(value op r.value);\
     }\
     rettype operator op (const T& r) const\
     {\
         return rettype(value op r);\
     }

#define MAKE_STRONG_TYPEDEF_OP_ASSIGN(op)\
     strong_typedef_class<T,Unique_T>& operator op \
     (const strong_typedef_class<T,Unique_T>& r) \
     {\
         value op r.value;\
         return *this;\
     }\
     strong_typedef_class<T,Unique_T>& operator op \
     (const T& r) \
     {\
         value op r;\
         return *this;\
     }

#define MAKE_STRONG_TYPEDEF_UNOP(op)\
     T operator op () const\
     {\
         return op value;\
     }


template< class T, class Unique_T>
struct strong_typedef_class {
     typedef T value_type;
     typedef strong_typedef_class<T,Unique_T> self_type;
     T value;
     strong_typedef_class()
     :value(T())
     {}

     strong_typedef_class(const T& v)
     :value(v)
     {}

     strong_typedef_class(const strong_typedef_class& v)
     :value(v.value)
     {}

     strong_typedef_class& operator=(const T&v)
     {
         value=T(v);
         return *this;
     }
     strong_typedef_class& operator=(const strong_typedef_class& v)
     {
         value=T(v.value);
         return *this;
     }

     /*
     operator T&()
     {
         return value;
     }
     */

     MAKE_STRONG_TYPEDEF_OP_CONST(bool, > )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, < )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, >= )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, <= )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, == )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, != )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, && )
     MAKE_STRONG_TYPEDEF_OP_CONST(bool, || )

     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, +)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, -)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, /)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, *)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, %)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, <<)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, >>)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, &)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, |)
     MAKE_STRONG_TYPEDEF_OP_CONST(self_type, ^)

     MAKE_STRONG_TYPEDEF_OP_ASSIGN( += )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( -= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( *= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( /= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( >>= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( <<= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( ^= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( &= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( |= )
     MAKE_STRONG_TYPEDEF_OP_ASSIGN( %= )

     MAKE_STRONG_TYPEDEF_UNOP(+)
     MAKE_STRONG_TYPEDEF_UNOP(-)
     MAKE_STRONG_TYPEDEF_UNOP(~)
     MAKE_STRONG_TYPEDEF_UNOP(!)

     strong_typedef_class<T,Unique_T>& operator ++ ()
     {
         ++value;
         return *this;
     }

     strong_typedef_class<T,Unique_T>& operator -- ()
     {
         --value;
         return *this;
     }

     strong_typedef_class<T,Unique_T>& operator ++ (int)
     {
         ++value;
         return *this;
     }

     strong_typedef_class<T,Unique_T>& operator -- (int)
     {
         --value;
         return *this;
     }
};

template<class T, class Unique_T>
std::ostream& operator<<(std::ostream& os, const
strong_typedef_class<T,Unique_T>& r)
{
     os << r.value;
     return os;
}

template<class T, class Unique_T>
std::istream& operator>>(std::istream& is,
strong_typedef_class<T,Unique_T>& r)
{
     is >> r.value;
     return is;
}

#define STRONG_TYPEDEF(base_type, typedef_name)\
     struct uniq_clas_for_strng_typdf__ ## typedef_name {};\
     typedef strong_typedef_class<base_type,  \
     uniq_clas_for_strng_typdf__ ## typedef_name > \
     typedef_name;


/////////////////// EXAMPLE /////////////////////

STRONG_TYPEDEF(double, volts_st);
STRONG_TYPEDEF(double, amps_st);
STRONG_TYPEDEF(double, ohms_st);
STRONG_TYPEDEF(double, watts_st);

watts_st GetWatts(volts_st v, amps_st a)
{
     return v.value * a.value;
}

watts_st GetWatts(amps_st a, ohms_st o)
{
     return a.value * a.value * o.value;
}

watts_st GetWatts(volts_st v, ohms_st o)
{
     return v.value * v.value / o.value;
}

#define PRINT(var) {std::cout<<#var<<": "<<var<<std::endl;}

int main()
{
     volts_st v = 12.0;
     amps_st  a = 5.99;
     ohms_st  o = 2.01;

     PRINT( v );
     PRINT( a );
     PRINT( o );
     PRINT( GetWatts(v,a) );
     PRINT( GetWatts(a,o) );
     PRINT( GetWatts(v,o) );

     // have to access ".value"
     // to convert to double.
     PRINT( sqrt(v.value) );

     // next lines should give compiler errors:
     // std::cout << GetWatts(o,v) << std::endl;
     // v = a;

}

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]




Author: "Siemel Naran" <SiemelNaran@KILL.att.net>
Date: 2 May 2003 12:06:11 -0400
Raw View
"Derek Ross" <dross@iders.ca> wrote in message news:DDfsa.75199

> The funny thing is, after I played around with strong
> typedefs for a while, they didn't seem as wonderful
> as I originally thought they would be.  Maybe that's
> why C++ didn't have them in the first place!

This seems pretty nice.  What went wrong?

Is it possible to get rid off macros?  Would something like this work

template <class T, const char * Name>
class strong_typedef_class {
   ...
};

extern const char *const text_volts;
const char *const text_volts = "Volts";

typedef strong_typedef_class<double, text_volts> Volts;

--
+++++++++++
Siemel Naran
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]