typeof: type registration

Hello everybody, Recently there was a discussion about a typeof emulation library. The library determines the type of an expression by passing it to a function template, encoding the type as a list of integers, "returning" them one-by-one via sizeof(), and decoding the type. One of the main problems of any such emulation is the need to associate types and templates with unique compile-time integral identifiers. This becomes even bigger problem, when expressions can contain types/templates from different libraries. It's not quite clear how to ensure uniqueness of identifiers in this case (GUID would be an option, but it's far too big to fit into an integer). An attempt was made to generate the identifiers automatically. However, since mechanisms to achieve this always work inside only one compilation unit, there is no way to preserve the same identifiers for the same entities throughout different compilation units. Hence, inevitably, we run into the ODR violation. An attempt to work this around by defining stuff in anonimous namespace, forces everything that uses this facility to also be defined in the anonimous namespace or, again, the ODR is violated. Although compilers don't seem to care much about ODR in this particular case (meta-functions only, no runtime constructs), somehow I feel uneasy to proceed with the solution that does not quite comply to the standard. And so, once again, I tried to come-up with a registration scheme that, on the one hand, would not violate the ODR, and on the other hand, would not put a significant burden on the end user -- the crutial condition for this library to be of any use at all. Here is this scheme: The typeof library registers primitive types, as well as some other standard stuff, like functions, pointers, references, arrays, consts, etc. If the user only wants any combination of those, no additional actions is required, such as the following type: int& (*)(char[20], double&) would be handled. If, in addition to this, the user wants to handle types from other libraries, such as Spirit, Lambda, etc., it works as following: - The typeof library #defines a preprocessor constant, currently called BOOST_TYPEOF_USER_GROUP, which is the next identifier after the last one it actually used. - The Spirit library registers its types against some symbolic identifiers. Only one per file is required (inside the same file __LINE__ does the job). Something looking similarly to the include guard seems like a decent choice. In addition, Spirit defines a separate header where it enumerates all these symbolic identifiers. This header looks something like this: <boost/spirit/groups.hpp> #ifndef SPIRIT_GROUPS_HPP_INCLUDED #define SPIRIT_GROUPS_HPP_INCLUDED #include <boost/spirit/typeof/typeof.hpp> enum { SPIRIT_REGISTER_HPP = BOOST_TYPEOF_USER_GROUP, SPIRIT_LAST }; #undef BOOST_TYPEOF_USER_GROUP #define BOOST_TYPEOF_USER_GROUP SPIRIT_LAST #endif//SPIRIT_GROUPS_HPP_INCLUDED IOW, the Spirit identifiers start where the typeof library identifiers ended, and BOOST_TYPEOF_USER_GROUP is, again, the next available. - The Lambda library does the same, etc. - The user combines all the groups in a single include, effectively chaining the enums: #ifndef GROUPS_HPP_INCLUDED #define GROUPS_HPP_INCLUDED #include <boost/spirit/groups.hpp> #include <boost/lambda/groups.hpp> #endif//GROUPS_HPP_INCLUDED - The user includes this file before any registration file provided by these libraries. Since the file contains only enums, the compile-time penalty is minimal. This insures that identifiers remain fixed across compilation units. - Whenever the user needs to register her own classes, she provides identifiers by any means she prefers, such as enum, etc., starting from BOOST_TYPEOF_USER_GROUP. See http://groups.yahoo.com/group/boost/files/typeof.zip (or Spirit repository, TYPEOF_DEV branch) for how it all works together. I appologize for such a long post (if you are still here :) ) Any comments? Regards, Arkadiy

On Jul 22, 2004, at 12:00 AM, Vertleyb wrote:
- The user combines all the groups in a single include, effectively chaining the enums:
Do the enums always have to be consecutive? I see no problem with keeping a central file containing the enum values for all Boost libraries. Then for the simplest cases (the user uses only Boost), typeof would "just work". Users would still have to extend the library using BOOST_TYPEOF_USER_GROUP, of course, but at least that's for their own code. Is it feasible?
Any comments?
Just reiterating that I think usability is more important than worrying about the ODR in this case.[*] Doug [*] Last summer I told a room full of compiler developers "It's an ODR violation, get over it", referring to a design to be integrated into their C++ compiler/library. They gagged, choked, and accepted the entire thing for the next release.
participants (2)
-
Doug Gregor
-
Vertleyb