One of missing operators in the C++ standard is the
typeof operator which returns the type-of given expression. It is often implemeted as a compiler extension, but is still missing from the Visual Studio's C++ compiler (7.1).
However, there are few
typeof implementations which could be used, probably all of them based on a very simple, but genious idea introduced by Bill Gibbons (http://www.accu-usa.org/2000-05-Main.html). In a short (feel free to skip this paragraph to the end since it could be hard for you to understand this), each type that will be used with a
typeof operation should be separately registered, which partially specializes (by a unique index) a class which contains registered type. Besides it, a new function overload is introduced, which, as a parameter, receives the type that is registering and, as an output, it returns an array that has a size of the unique index used in the previous class.
typeof operator is now simple to implement: you have an expression you need a type of; call function with the expression as a parameter; calculate a
sizeof return value; put the size in a class template parameter and receive a type stored there, which is equal to the expression type! Besides it, all of this is calculated at the compile time, so, no actual function definitions are needed, meaning, no additional code is introduced! A brilliant idea which is useable with very small consequences (every type to be used should be registered and there is a small hit on compiler speed).
Although it's not documented (or I haven't found it in documentation), it appears that Boost's MPL contains a typeof operator implementation that applies to the above pattern:
BOOST_MPL_AUX_TYPEOF(_, aa1) *aa2 = &aa1;
The drawbacks of Boost' solution, in my opinion, are:
- It's undocumented.
- The syntax is extemly ugly.
- You have to manually feed the registration process with an unique index for every type.
- You have to register pointer and constant types separatelly.
- You have to use typedefs if you want to register template instances, since colons cannot be put in define macro parameter.
- Error messages are non-existent.
I've tried and, hopefully, succeeded in finding workarounds for all listed issues.
Here we go:
- You are just looking at it! :)
- Syntax is much more clear now! Type registration is done this way:
register_type hash_table<int, char *> for_typeof;
...while the usage is as simple as this:
hash_table<int, char *> var;
typeof(&var) ptr = &var;
for(typeof(var)::iterator it = var.begin(); it != var.end(); it++)
You can see that the code becomes more readable, you have to type less and, in the case type (especially collection classes) changes, you have to modify only at the one place.
Note that that if you provide a
typedef polluted with pointers, reference or
volatile modifiers during the registration process, they will be removed for you. Also, feel free to use the typeof operator wherever you want, for local variables, global variables, class members, base classes and so on.
- As it can be seen above, you only need a type during the registration! Unique index is provided by a
__COUNTER__ macro found in new Visual Studio. However, don't think it makes the implementation trivial - Boost's preprocessor library and template specialization have been heavily used since every usage of the
__COUNTER__ macro will give you the different number, while indice had to be used on many places during the registration process!
- By using Boost's preprocessor library (which is at the same time very powerful, but very limiting), pointers for the type are automatically registered. A constant
TYPEOF_POINTER_LEVELS (defaults to the value of three) defines how many pointers will be registered. In practice, the default value will be more than enough; higher values (50, for example) will make compiler very slow, while the limit is about 80. Also, a const modified at the lowest level will also be registered (an implementation for other combinations would be very complicated).
To make this more clear, after registration, with default pointer_levels value, you'll be able to work with following types:
hash_table<int, char *>
hash_table<int, char *> *
const hash_table<int, char *> *
hash_table<int, char *> **
const hash_table<int, char *> **
hash_table<int, char *> ***
const hash_table<int, char *> ***
- Fixed, without additional comment. :)
- If you'll try to apply the typeof operator to an unregistered type, in a second error message, the typeof_type_not_registered type will be mentioned, which should make more clear what just happened.
I'm looking forward to see comments, improvements, suggestions and more simple solutions!
(untested with previous versions)