
Warning: This is a fairly lengthy post, as I have had a difficult time putting my thoughts into words (also, I have had very little free time lately -- though it is hard to say that with a straight face since I just spent the holiday weekend skiiing). If you want to skip my monotonous musings, read the summary only, and possibly skip down a few paragraphs until you see a significant amout of vertical white space, then read some more technical points. I would really appreciate any thoughts or insights, as I am quite frankly not very satisfied with my own. SUMMARY: I would like to delay proposing a typeid() replacement. Instead, I'd like to submit my testsuite, and ask people to run it on various platforms and report the results. This will help us decide how best to approach this seemingly simple, but very difficult, subject. I would like to propose a boost::type_info class now (or very soon). Meaningful instances of boost::type_info will be constructed from a std::type_info resulting from a native typeid() call. Once we figure out what route to take wrt typeid(), then I think it can be used in a very straight forward manner. Now for some rumblings, where I try to sort out my experiences with typeid (I apologize in advance for the lack of polish, but I want to get this out for comment because I am going out of town Friday afternoon, and will not be back until Sunday night). A while back, I had some of my own code to use typeid/type_info. The code was inspired by the TypeInfo class in "Modern C++ Design" by Andrei Alexandrescu. However, I ran into some issues (namely the infamous g++ shared library problem). A search of boost found an implementation in Boost.Python. As has been mentioned in the past, this seems like a useful utility to have around, so I made an attempt to bring it out of Boost.Python, and give it life of its own. David suggested that such a small exposure is a good candidate for a fast track review, so I naively thought that meant it would be a small amount of work. Along the way, I ran into several portability issues, and decided to make sure the code had the best typeid/type_info support I could imagine. Unfortunately, this took me down a very twisted highway. I could not find an existing test suite, so I wrote my own, based on the standard (5.2.8 and 18.5.1). Well, this turned into a nightmare, because I have had a hard time finding any compiler that will pass all my tests. I have had to move to gcc 3.4 to get most of them to pass, and still some fail (though it may be due to my tests... I am still looking into that). I will say that I now know more about typeid() than I ever thought I'd want to know (I could quite possibly quote verbatum section 5.2.8, and a fair bit of 18.5.1 to boot). Anyway, getting a portable typeid/type_info library working is not exactly as easy as it appears. A previous post of mine attributes most typeid problems to older msvc/intel compilers. This is only mostly true. They are the worst, because they do not even try to remove the top-level cv-qualifiers. However, even relatively recent versions of gcc has had problems with this in esoteric cases (multidimensional array with cv qualifiers mixed with typedefs). All this to say that I have my doubts that many compilers fully support typeid() correctly. To top it all off, many implementations have trouble honoring the comparison mechanism across separate shared libraries (as noted in the Boost.Python implementation), so there are some workarounds needed for type_info as well. Since I have seen so many problems, I am no longer certain that the review of typeid can be done quickly. While the implementation in Boost.Python works well, it also has several holes, so I do not think it wise to simply "bring it out" into boost. Thus, I have made an attempt to "industrialize" it. With this in mind, I thought I'd give a rundown of the major issues. I recently posted some of my concerns, but due to the length of that post, and possibly its ramblings, I have not seen any replies. Yes, I know, this one is longer, and possibly more "rambling" but I am hopeful yet ;-) I will leave the more minor issues for later, but would really like some input on the bigger ones. The library, as used in Boost.Python, relies on calling the no-parameter template function, type_id, to get the type info object. Use of typeid() by itself is absent, because of the problem with compilers getting the typeid() implementation correct. For example: struct foo { /* ... */ }; boost::python::type_info ti = boost::python::type_id< foo >(); Unfortunately, boost::python::type_id<>() has a couple major drawbacks (and a number of "minor" ones). 1. It only supports type-id calls, with a specific type passed as a template parameter. The ability to compute type_info based on the result of an expression is scant (a bit more functionality can possibly be obtained with more tricks like the ingenious typeof() stuff recently posted). 2. To add support for expressions and lvalues, overloads of type_id() can be provided. This works reasonably well (with enough machinery to get around compiler problems), but the spec for typeid() says that the expression is not supposed to be evaluated (unless the expression is an lvalue of a polymorphic type, or dereferences a pointer to a polymorphic type). I have yet to see a way to call a function and prevent the expression from being evaluated (maybe with some modern tricks and is_polymorphic -- but we are then probably leaving several compilers behind as well). Also, I have been unable to get the "workaround" to throw std::bad_typeid when dereferencing a null pointer, as specified in 5.2.8.2). 3. For compilers with bad cv-qualifier support wrt typeid(), it requires a fair amount of machinery to get rid of the cv-qualifiers. Unfortunately, the same machinery makes it difficult to preserve the polymorphic requirements of 5.2.8.2, and I have yet to find the right code to get this to work (though I think it may be possible). Thus, we face a dilemma. Either always use the native typeid(), knowing that your compiler may not fully support it "by the book" or provide some workaround, that will not provide everything either. By fixing some things, others are broken. We are left with some options: 1. Always use the native typeid() in code, and live with what the compiler does. 2. Always use a "workaround" and live with whatever level of "brokeness" that provides. I am not convinced that we can get a consistent level of brokeness for all compilers, though it is more likely to be close for all compilers than just using typeid(). 3. Provide a macro BOOST_TYPEID(), which is set depending on which compiler is being used, to get the "best" effect. Depending on the day, I feel differently about which option I like. Thus, I have written a fairly extensive set of tests for native typeid(). I feel fairly certain that they can tell us what to expect from any compiler relative to typeid conformance. We could use those tests results, from "all" the supported platforms to see where we are (my access to compilers/platforms is quite limited). Maybe if we had a better idea about what each of the "major" platoforms do/not support we could get a better idea as to how we want to proceed. In any case, I do not think this will be super quick. So, let's move to type_info. I think this one is a bit more clear (though we still need some compiler workarounds). However, the only real workarounds I have found so far involve "broken" comparison operators. I think these are fairly well known, and mostly solved. I also have a fairly extensive set of tests for native std::type_info, as well as the new boost::type_info. However, I am still hung up on the whole typeid thing stated above. I tend to think that most use of typeid() will work as expected. The "major" problems concern quite old compilers (I think), and some of the problems in more modern compilers are in the "corners" of usage. Thus, it makes sense to get boost::type_info in place, and wait until we have some test results to see what is the propor course of action for typeid. Thanks, and if you read this far, maybe YOU should go skiing ;-)