[TypeIndex] Peer review period for library acceptance begins, ending Thurs 21st Nov

Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes: 1. Should this library be accepted into Boost? 2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!) Peer review ends on Thursday 21st Nov, ten days from today. Based on your feedback, at that point I will decide if I recommend TypeIndex for inclusion in my report to the review wizards. Comments can be posted to boost@lists.boost.org if you expect others to comment on your post, or to me privately if you wish your comment to not be made public. What is Boost.TypeIndex? TypeIndex performs three main functions: 1. It provides a consistent, well defined, portable boost::typeid() implementation with a consistent, well defined, portable boost::type_info class implementation which mirrors std::type_info. Implementation-specific weirdnesses (e.g. std::type_info::raw_name(), the fact the hash_code is often terrible and collides frequently) are abstracted out into a single, portable API. 2. It provides the ability to convert a type into a uniquely identifiable, container indexable, boost::type_info instance (e.g. &typeid(T) or C++11 class std::type_index) with RTTI disabled, thereby removing the need for requiring RTTI enabled for many type_info use cases. Any features which require RTTI are very clearly denominated in the API's name. 3. It allows the following Boost libraries to eliminate their dependency on RTTI which is a big win for embedded systems use, and it supplies patches for these libraries replacing RTTI std::type_info with boost::type_info. Feedback from the maintainers and users of these Boost libraries is *particularly* welcomed: Any, Graph, Property Map, Property Tree, Test, Variant, Xpressive I believe that TypeIndex meets the Boost library requirements at http://www.boost.org/development/requirements.html, and I have personally verified that it builds and passes all unit tests on GCC 4.6, clang 3.0 and MSVCs 10-12 [1]. I should add that Antony has already done three rounds of changes according to my feedback, and my thanks to him for being so dilligent and responsive. NOTE: Please read the TypeIndex documentation (linked to below) before asking any questions e.g. about potential code bloat etc. You'll probably find the answer already there. Source code: https://github.com/apolukhin/type_index/zipball/master Github: https://github.com/apolukhin/type_index Documentation: http://apolukhin.github.com/type_index/index.html Any questions about topics not in the documentation? Please do ask. [1]: A single unit test currently always is reported as failing to link correctly on MSVC. Antony believes this to be a bug in Windows bjam, as the Jamfile marks the link as expected to fail using link-fail but bjam does not respect this on Windows in this one use case scenario (yet weirdly the other expected link failures work fine!). Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

AMDG On 11/12/2013 11:34 AM, Niall Douglas wrote:
[1]: A single unit test currently always is reported as failing to link correctly on MSVC. Antony believes this to be a bug in Windows bjam, as the Jamfile marks the link as expected to fail using link-fail but bjam does not respect this on Windows in this one use case scenario (yet weirdly the other expected link failures work fine!).
I'm aware of this bug. link-fail doesn't work with the msvc toolset, because there are two separate updating actions (msvc.link and msvc.manifest). FAIL_EXPECTED currently requires that /every/ updating action fails. No one was using it before, so put it at low priority. In Christ, Steven Watanabe

On 12 Nov 2013 at 12:54, Steven Watanabe wrote:
I'm aware of this bug. link-fail doesn't work with the msvc toolset, because there are two separate updating actions (msvc.link and msvc.manifest). FAIL_EXPECTED currently requires that /every/ updating action fails. No one was using it before, so put it at low priority.
That is very useful to know indeed, and explains the problem. Could a workaround for TypeIndex be to disable the generation of the manifest file? For unit test executables - especially ones expected to fail to link - we don't care, so is disabling that second step possible? Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

Le 12/11/13 20:34, Niall Douglas a écrit :
What is Boost.TypeIndex?
TypeIndex performs three main functions:
Any questions about topics not in the documentation? Please do ask.
|
Hi,
First of all, thanks for submitting this library for review.
I've some minor typos remarks, questions and suggestions.
* In
http://apolukhin.github.io/type_index/boost_typeindex/getting_started.html
boost::type_info| is a drop-in replacement for |std::type_index
s/||std::type_index/||std::type_info
* In
http://apolukhin.github.io/type_index/boost_typeindex_header_reference.html#...
Shouldn't |||std::hash needs to be specialized for boost:index?
|template <> struct std::hashboost::type_index;
The same applies for boost::type_info.
* In http://apolukhin.github.io/type_index/boost/type_info.html
These functions
|||
//public static functions http://apolukhin.github.io/type_index/boost/type_info.html#idp5825712-bb
template<typename T> static const boost::type_info http://apolukhin.github.io/type_index/boost/type_info.html & construct http://apolukhin.github.io/type_index/boost/type_info.html#idp5826208-bb() noexcept;
template<typename T>
static const boost::type_info http://apolukhin.github.io/type_index/boost/type_info.html & construct_with_cvr http://apolukhin.github.io/type_index/boost/type_info.html#idp5829664-bb() noexcept;
template<typename T>
static const type_info http://apolukhin.github.io/type_index/boost/type_info.html & construct_rtti_only http://apolukhin.github.io/type_index/boost/type_info.html#idp5833264-bb(T &) noexcept;
template<typename T> static const type_info http://apolukhin.github.io/type_index/boost/type_info.html & construct_rtti_only http://apolukhin.github.io/type_index/boost/type_info.html#idp5837360-bb(T *);
|
||are in some way duplicates of |
||
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id http://apolukhin.github.io/type_index/boost/type_id.html();
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id_with_cvr http://apolukhin.github.io/type_index/boost/type_id_with_cvr.html();
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id_rtti_only http://apolukhin.github.io/type_index/boost/type_id_rtti_on_idp5863488.html(T &);
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id_rtti_only http://apolukhin.github.io/type_index/boost/type_id_rtti_on_idp5867296.html(T *);
|
Defining the preceding functions factories friend of boost::type_info,
could be enough.
* Why don't replace
|
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id http://apolukhin.github.io/type_index/boost/type_id.html();
by
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id http://apolukhin.github.io/type_index/boost/type_id.html(T & v);
template<typename T> const type_info http://apolukhin.github.io/type_index/boost/type_info.html & type_id http://apolukhin.github.io/type_index/boost/type_id.html(T * v=0);
so that the user can use
class D { /* ... */ };
D d1;
const D d2;
boost::type_id(d1) == boost::type_id(d2); // yields true
boost::type_id<D>() == boost::type_id<const D>(); // yields true
boost::type_id<D>() == boost::type_id(d2); // yields true
boost::type_id<D>() == boost::type_id

2013/11/13 Vicente J. Botet Escriba
* In http://apolukhin.github.io/type_index/boost_typeindex/getting_started.html boost::type_info| is a drop-in replacement for |std::type_index
Fixed
* In http://apolukhin.github.io/type_index/boost_typeindex_header_reference.html#...
Shouldn't |||std::hash needs to be specialized for boost:index? |template <> struct std::hashboost::type_index;
The same applies for boost::type_info.
That's a good question for many of the Boost libraries. One of the policies in Boost - is not to mess with std:: namespace. On the other hand specializing std::hash is a common solution in C++11. Many Boost libraries just do not specialize std::hash, so I followed that design.
* In http://apolukhin.github.io/type_index/boost/type_info.html These functions |||
//public static functions <http://apolukhin.github.io/ type_index/boost/type_info.html#idp5825712-bb> template<typename T> static const boost::type_info < http://apolukhin.github.io/type_index/boost/type_info.html> & construct http://apolukhin.github.io/type_index/boost/type_info.html#idp5826208-bb() noexcept; template<typename T> static const boost::type_info < http://apolukhin.github.io/type_index/boost/type_info.html> & construct_with_cvr <http://apolukhin.github.io/ type_index/boost/type_info.html#idp5829664-bb>() noexcept; template<typename T> static const type_info < http://apolukhin.github.io/type_index/boost/type_info.html> & construct_rtti_only <http://apolukhin.github.io/ type_index/boost/type_info.html#idp5833264-bb>(T &) noexcept; template<typename T> static const type_info < http://apolukhin.github.io/type_index/boost/type_info.html> & construct_rtti_only <http://apolukhin.github.io/ type_index/boost/type_info.html#idp5837360-bb>(T *);
| ||are in some way duplicates of | ||
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id <http://apolukhin.github.io/ type_index/boost/type_id.html>(); template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id_with_cvr < http://apolukhin.github.io/type_index/boost/type_id_with_cvr.html>(); template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id_rtti_only < http://apolukhin.github.io/type_index/boost/type_id_rtti_ on_idp5863488.html>(T &); template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id_rtti_only < http://apolukhin.github.io/type_index/boost/type_id_rtti_ on_idp5867296.html>(T *);
| Defining the preceding functions factories friend of boost::type_info, could be enough.
Added a note to member functions that they work exactly like functions in boost:: namespace. Did not removed text (having it in-place looks more user friendly, than forcing user to go and search the description oin some other place/method) * Why don't replace
|
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id <http://apolukhin.github.io/ type_index/boost/type_id.html>();
by
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id <http://apolukhin.github.io/ type_index/boost/type_id.html>(T & v);
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id <http://apolukhin.github.io/ type_index/boost/type_id.html>(T * v=0);
so that the user can use
class D { /* ... */ }; D d1; const D d2; boost::type_id(d1) == boost::type_id(d2); // yields true boost::type_id<D>() == boost::type_id<const D>(); // yields true boost::type_id<D>() == boost::type_id(d2); // yields true boost::type_id<D>() == boost::type_id
(); // yields true
User can do exactly the same using current interface:
class D { /* ... */ };
D d1;
const D d2;
boost::type_id_rtti_only(d1) == boost::type_id_rtti_only(d2); // yields true
boost::type_id<D>() == boost::type_id<const D>(); // yields true
boost::type_id<D>() == boost::type_id_rtti_only(d2); // yields true
boost::type_id<D>() == boost::type_id
|||* Is there any reason to name |type_id_rtti_only|| instead of type_id to emulate the std typeid behavior. I would reverse the names
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id <http://apolukhin.github.io/ type_index/boost/type_id.html>(T & v); // behaves like typeid(v)
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id <http://apolukhin.github.io/ type_index/boost/type_id.html>(T * v); // behaves like typeid(v)
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id_no_rtti < http://apolukhin.github.io/type_index/boost/type_id_rtti_ on_idp5863488.html>(T &); //heavier but doesn't need rtti
template<typename T> const type_info <http://apolukhin.github.io/ type_index/boost/type_info.html> & type_id_no_rtti < http://apolukhin.github.io/type_index/boost/type_id_rtti_ on_idp5863488.html>(T *);//heavier but doesn't need rtti
Names were given according to the following logic: * TypeIndex library promises that it works without RTTI * calls that do not work without RTTI must be explicitly marked * calls that do work without RTTI - is just what was promised by the library, no need to explicitly mark that the call does not requires RTTI In both situation we can not 100% emulate the syntax typeid: typeid(Type) // this can be done by macro, but macros are not good typeid(variable) * why do you need template_index it it is the same as template_info?
This is done for uniformity: if there is a type_info and type_index, than it must be template_info and template_index. I've tried to implement all the functionality of type_index in type_info, but that attempt failed (so we have two classes). Either type_info was not able to copy, or following code failed to compile: // Note the std:: namespace! std::type_index t = boost::type_info_with_cvr<const int>();
* What about separating NORTTI inBOOST_TYPE_INDEX_FORCE_ NORTTI_COMPATIBILITY?
Fixed
* what is behind the name template in template_info?what about renaming it to type_info_ptr?
`template` is an attempt to reflect in name its behavior. `template_info` == information about template parameter type
* stating that something works as the standard C++, would either need a reference to a version, or describe explicitly the bahavior on the library documentation.
I've missed the point, where in docs must be the note about version added?
Best, Vicente
Great thanks for all the comments! I've updated the docs and sources, -- Best regards, Antony Polukhin

On 13/11/2013 20:22, Quoth Antony Polukhin:
Names have "_rtti_only" to warn user that this call requires RTTI. This must ring a bell and user may switch to type_id<D> version, which is more portable. type_id_rtti_only is more explicit, so I like it more. But if there'll be many recomendations during review period to switch names to boost::type_id, I'll do that. [...] Names were given according to the following logic: * TypeIndex library promises that it works without RTTI * calls that do not work without RTTI must be explicitly marked * calls that do work without RTTI - is just what was promised by the library, no need to explicitly mark that the call does not requires RTTI
Couldn't this be resolved by changing the first to "TypeIndex library promises to be an enhanced implementation of standard typeid". Then you could just use: * boost::type_id<Type>() // typeid(Type) * boost::type_id(variable) // typeid(variable) Both would work with or without RTTI but the second would only report the declared type of the variable in the absence of RTTI (which is what typeid does for sliced value types anyway). Granted that you're no longer being explicit about RTTI safety or not in the actual method name, but I would hope that library authors who wish their libraries to work either way would test accordingly, so it should not matter. It seems to me that you're already aiming "higher" than bare-bones no-RTTI support with this library, with the name demangling and cv-preservation features for example. (Though please see my other reply regarding demangling.)

2013/11/13 Gavin Lambert
On 13/11/2013 20:22, Quoth Antony Polukhin:
Names have "_rtti_only" to warn user that this call requires RTTI. This
must ring a bell and user may switch to type_id<D> version, which is more portable. type_id_rtti_only is more explicit, so I like it more. But if there'll be many recomendations during review period to switch names to boost::type_id, I'll do that.
[...]
Names were given according to the following logic:
* TypeIndex library promises that it works without RTTI * calls that do not work without RTTI must be explicitly marked * calls that do work without RTTI - is just what was promised by the library, no need to explicitly mark that the call does not requires RTTI
Couldn't this be resolved by changing the first to "TypeIndex library promises to be an enhanced implementation of standard typeid".
Then you could just use: * boost::type_id<Type>() // typeid(Type) * boost::type_id(variable) // typeid(variable)
Both would work with or without RTTI but the second would only report the declared type of the variable in the absence of RTTI (which is what typeid does for sliced value types anyway).
This looks very error prone. In current implementation disabling RTTI leads to compile errors in case of an attempt to determinate type at runtime. Using your approach code will compile, behavior of functions will silently change and user will be debugging the application. Or even won't find the issue and release a bogus program.
Granted that you're no longer being explicit about RTTI safety or not in the actual method name, but I would hope that library authors who wish their libraries to work either way would test accordingly, so it should not matter.
Why force them to test code for errors, that can be detected and avoided at compile-time?
It seems to me that you're already aiming "higher" than bare-bones no-RTTI support with this library, with the name demangling and cv-preservation features for example. (Though please see my other reply regarding demangling.)
Well may be a little bit :) But those features are widely used and looks like type_info is the correct place for them. -- Best regards, Antony Polukhin

On 13/11/2013 08:34, Quoth Niall Douglas:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. [...] NOTE: Please read the TypeIndex documentation (linked to below) before asking any questions e.g. about potential code bloat etc. You'll probably find the answer already there.
The docs for .name_demangled() indicate "Readable names may also differ between compilers: struct user_defined_type, user_defined_type." Is it feasible to enforce some sort of compiler-independent uniformity on this (eg. guaranteeing that even if the native typeid output would insert "struct" or "class", name_demangled() would strip it off before returning it)? It would be good for code portability if users didn't have to worry about possibly externally stripping such things to produce "nice" output, or consistent output between compilers. I'm also not sure "name_demangled" is a good method name, as "name" being mangled is a GCC implementation detail that is not true in MSVC, for example. I would prefer something more generic, such as "long_name" or "friendly_name", or like MSVC using "raw_name" in place of the current "name", and "name" in place of the current "name_demangled".

2013/11/13 Gavin Lambert
On 13/11/2013 08:34, Quoth Niall Douglas:
Boost community feedback is requested for the formal peer review of
the TypeIndex library by Antony Polukhin.
[...]
NOTE: Please read the TypeIndex documentation (linked to below)
before asking any questions e.g. about potential code bloat etc. You'll probably find the answer already there.
The docs for .name_demangled() indicate "Readable names may also differ between compilers: struct user_defined_type, user_defined_type."
Is it feasible to enforce some sort of compiler-independent uniformity on this (eg. guaranteeing that even if the native typeid output would insert "struct" or "class", name_demangled() would strip it off before returning it)? It would be good for code portability if users didn't have to worry about possibly externally stripping such things to produce "nice" output, or consistent output between compilers.
This is almost impossible: different compilers decorate names differently. This means that for each compiler we need to write parser/lexer that: * puts const, volatile, rvalue, reference at correct position (always after the type or always before) * strips away class, struct, __cdecl* * unifies template parameters representation * makes other unifications (array representations, wchar_t and __wchar_t unifications and so on...) This may be done some day and `name_portable()` method can be added. But I'm afraid this won't happen soon. I'm also not sure "name_demangled" is a good method name, as "name" being
mangled is a GCC implementation detail that is not true in MSVC, for example. I would prefer something more generic, such as "long_name" or "friendly_name", or like MSVC using "raw_name" in place of the current "name", and "name" in place of the current "name_demangled".
According to C++03 and C++11 Standard type_info::name() must return const char*. Getting readable name requires some work and an internal buffer inside boost::type_info. This looks like a bad solution (so "raw_name()" and "name()" won't fit). MSVC also mangles names, but hides that from user. So as for me, name_demangled() looks not bad. -- Best regards, Antony Polukhin

On 13/11/2013 20:46, Quoth Antony Polukhin:
This is almost impossible: different compilers decorate names differently. This means that for each compiler we need to write parser/lexer that: * puts const, volatile, rvalue, reference at correct position (always after the type or always before) * strips away class, struct, __cdecl* * unifies template parameters representation * makes other unifications (array representations, wchar_t and __wchar_t unifications and so on...)
This may be done some day and `name_portable()` method can be added. But I'm afraid this won't happen soon.
Granted it's hard to sort out all the cases. But solving the common cases for the common compilers (eg. leading struct) should be easy, and people could chip away at the other cases over time if they cared to.
According to C++03 and C++11 Standard type_info::name() must return const char*. Getting readable name requires some work and an internal buffer inside boost::type_info. This looks like a bad solution (so "raw_name()" and "name()" won't fit).
But you're not implementing std::type_info, you're implementing boost::type_info, so you should be free to return a std::string if you feel like it. You're already changing the behaviour on MSVC, because std::type_info::name returns the long name but boost::type_info::name returns the short name. Or how about: * const char *name() : returns whatever std::type_info::name does [if RTTI] * std::string short_name() : returns the raw/mangled name * std::string long_name() : returns the long/demangled name Or flip the components (name_short and name_long) if you prefer; it sorts better but reads worse that way, I think. (With RTTI disabled, all three would probably return the same value.)

2013/11/13 Gavin Lambert
On 13/11/2013 20:46, Quoth Antony Polukhin:
This is almost impossible: different compilers decorate names differently.
This means that for each compiler we need to write parser/lexer that: * puts const, volatile, rvalue, reference at correct position (always after the type or always before) * strips away class, struct, __cdecl* * unifies template parameters representation * makes other unifications (array representations, wchar_t and __wchar_t unifications and so on...)
This may be done some day and `name_portable()` method can be added. But I'm afraid this won't happen soon.
Granted it's hard to sort out all the cases. But solving the common cases for the common compilers (eg. leading struct) should be easy, and people could chip away at the other cases over time if they cared to.
According to C++03 and C++11 Standard type_info::name() must return const
char*. Getting readable name requires some work and an internal buffer inside boost::type_info. This looks like a bad solution (so "raw_name()" and "name()" won't fit).
But you're not implementing std::type_info, you're implementing boost::type_info, so you should be free to return a std::string if you feel like it. You're already changing the behaviour on MSVC, because std::type_info::name returns the long name but boost::type_info::name returns the short name.
This will break the ability of TypeIndex to be a drop-in replacement for typeid: boost::any a; ... const char* m = a.type().name(); // with boost::type_info this would be impossible
Or how about: * const char *name() : returns whatever std::type_info::name does [if RTTI] * std::string short_name() : returns the raw/mangled name * std::string long_name() : returns the long/demangled name
Or flip the components (name_short and name_long) if you prefer; it sorts better but reads worse that way, I think.
(With RTTI disabled, all three would probably return the same value.)
This is a good idea, thanks! Using it less user code will be broken. Do you like the following names: * const char* name() // minor behavior change on MSVC * const char* name_mangled() // this method must be added * std::string name_demangled() // remains exactly the same -- Best regards, Antony Polukhin

On Wed, Nov 13, 2013 at 1:28 PM, Antony Polukhin
2013/11/13 Gavin Lambert
Or how about: * const char *name() : returns whatever std::type_info::name does [if RTTI] * std::string short_name() : returns the raw/mangled name * std::string long_name() : returns the long/demangled name
Or flip the components (name_short and name_long) if you prefer; it sorts better but reads worse that way, I think.
(With RTTI disabled, all three would probably return the same value.)
This is a good idea, thanks! Using it less user code will be broken.
Do you like the following names: * const char* name() // minor behavior change on MSVC * const char* name_mangled() // this method must be added * std::string name_demangled() // remains exactly the same
I haven't had the chance to review the library (yet), but I second that boost::type_info::name() should be equivalent to std::type_info::name(), including MSVC. All special logic of demangling should be implemented in a new function, like name_demangled (and let me suggest a few other names for it - readable_name(), pretty_name()). name_mangled() is controversial because formally you have no guaranteed way to acquire a mangled name of the type. Some compilers provide it, others don't. I assume, you don't want to implement mangling algorithms for these compilers, so I'm in favor of removing this function or at least changing its semantics and name to something less obligatory, like raw_name() or underlying_name().

2013/11/13 Andrey Semashev
On Wed, Nov 13, 2013 at 1:28 PM, Antony Polukhin
wrote: 2013/11/13 Gavin Lambert
Or how about: * const char *name() : returns whatever std::type_info::name does [if RTTI] * std::string short_name() : returns the raw/mangled name * std::string long_name() : returns the long/demangled name
Or flip the components (name_short and name_long) if you prefer; it sorts better but reads worse that way, I think.
(With RTTI disabled, all three would probably return the same value.)
This is a good idea, thanks! Using it less user code will be broken.
Do you like the following names: * const char* name() // minor behavior change on MSVC * const char* name_mangled() // this method must be added * std::string name_demangled() // remains exactly the same
I haven't had the chance to review the library (yet), but I second that boost::type_info::name() should be equivalent to std::type_info::name(), including MSVC.
All special logic of demangling should be implemented in a new function, like name_demangled (and let me suggest a few other names for it - readable_name(), pretty_name()).
name_mangled() is controversial because formally you have no guaranteed way to acquire a mangled name of the type. Some compilers provide it, others don't. I assume, you don't want to implement mangling algorithms for these compilers, so I'm in favor of removing this function or at least changing its semantics and name to something less obligatory, like raw_name() or underlying_name().
Agreed. People may use auto-fill in IDE a lot (I do), so maybe starting methods from name_* is more auto-fill friendly: * const char* name() // same as std::type_info::name() * const char* name_raw() // * std::string name_pretty() // was name_demangled() In this way you just type name_ and see all the available name methods. -- Best regards, Antony Polukhin

On Wed, Nov 13, 2013 at 2:02 PM, Antony Polukhin
2013/11/13 Andrey Semashev
On Wed, Nov 13, 2013 at 1:28 PM, Antony Polukhin
wrote: 2013/11/13 Gavin Lambert
Or how about: * const char *name() : returns whatever std::type_info::name does [if RTTI] * std::string short_name() : returns the raw/mangled name * std::string long_name() : returns the long/demangled name
Or flip the components (name_short and name_long) if you prefer; it sorts better but reads worse that way, I think.
(With RTTI disabled, all three would probably return the same value.)
This is a good idea, thanks! Using it less user code will be broken.
Do you like the following names: * const char* name() // minor behavior change on MSVC * const char* name_mangled() // this method must be added * std::string name_demangled() // remains exactly the same
I haven't had the chance to review the library (yet), but I second that boost::type_info::name() should be equivalent to std::type_info::name(), including MSVC.
All special logic of demangling should be implemented in a new function, like name_demangled (and let me suggest a few other names for it - readable_name(), pretty_name()).
name_mangled() is controversial because formally you have no guaranteed way to acquire a mangled name of the type. Some compilers provide it, others don't. I assume, you don't want to implement mangling algorithms for these compilers, so I'm in favor of removing this function or at least changing its semantics and name to something less obligatory, like raw_name() or underlying_name().
Agreed.
People may use auto-fill in IDE a lot (I do), so maybe starting methods from name_* is more auto-fill friendly:
* const char* name() // same as std::type_info::name() * const char* name_raw() // * std::string name_pretty() // was name_demangled()
In this way you just type name_ and see all the available name methods.
IMHO, it's better when the names differ from the beginning, so you don't have to select the variant in the combo-box. It's enough to just press 'n', 'r' or 'p' to get the required function first in the list. Also, some IDE's allow to select auto-completion choices based on substrings in any part of the function name, not just the beginning. In any case, I think a clear name is more important than trying to make it work nicely in a particular IDE. There are many IDEs, of varying qualities and levels of sophistication, and in the end the only thing that matters is the code.

2013/11/13 Andrey Semashev
On Wed, Nov 13, 2013 at 2:02 PM, Antony Polukhin
wrote: 2013/11/13 Andrey Semashev
On Wed, Nov 13, 2013 at 1:28 PM, Antony Polukhin
wrote: 2013/11/13 Gavin Lambert
Or how about: * const char *name() : returns whatever std::type_info::name does [if RTTI] * std::string short_name() : returns the raw/mangled name * std::string long_name() : returns the long/demangled name
Or flip the components (name_short and name_long) if you prefer; it sorts better but reads worse that way, I think.
(With RTTI disabled, all three would probably return the same value.)
This is a good idea, thanks! Using it less user code will be broken.
Do you like the following names: * const char* name() // minor behavior change on MSVC * const char* name_mangled() // this method must be added * std::string name_demangled() // remains exactly the same
I haven't had the chance to review the library (yet), but I second that boost::type_info::name() should be equivalent to std::type_info::name(), including MSVC.
All special logic of demangling should be implemented in a new function, like name_demangled (and let me suggest a few other names for it - readable_name(), pretty_name()).
name_mangled() is controversial because formally you have no guaranteed way to acquire a mangled name of the type. Some compilers provide it, others don't. I assume, you don't want to implement mangling algorithms for these compilers, so I'm in favor of removing this function or at least changing its semantics and name to something less obligatory, like raw_name() or underlying_name().
Agreed.
People may use auto-fill in IDE a lot (I do), so maybe starting methods from name_* is more auto-fill friendly:
* const char* name() // same as std::type_info::name() * const char* name_raw() // * std::string name_pretty() // was name_demangled()
In this way you just type name_ and see all the available name methods.
IMHO, it's better when the names differ from the beginning, so you don't have to select the variant in the combo-box. It's enough to just press 'n', 'r' or 'p' to get the required function first in the list. Also, some IDE's allow to select auto-completion choices based on substrings in any part of the function name, not just the beginning.
In any case, I think a clear name is more important than trying to make it work nicely in a particular IDE. There are many IDEs, of varying qualities and levels of sophistication, and in the end the only thing that matters is the code.
Then it will be: * const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled() -- Best regards, Antony Polukhin

On Wed, Nov 13, 2013 at 2:16 PM, Antony Polukhin
Then it will be:
* const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled()
Looks great to me.

2013/11/13 Andrey Semashev
On Wed, Nov 13, 2013 at 2:16 PM, Antony Polukhin
wrote: Then it will be:
* const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled()
Looks great to me.
I like it too. Now it is a drop in replacement that supports even the MSVC extensions. -- Best regards, Antony Polukhin

On 13 Nov 2013 at 14:28, Antony Polukhin wrote:
* const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled()
Looks great to me.
I like it too. Now it is a drop in replacement that supports even the MSVC extensions.
I'm afraid I disagree - you're breaking the interface contract with std::type_info when RTTI is off. Previous commenters may not realise that template_info::name() does NOT return the same value as type_info::name() when RTTI is off. It returns an internal unique const char * value, that's all. My concern is that MSVC's raw_name() does something very explicit: if you read http://msdn.microsoft.com/en-us/library/vstudio/70ky2y6k.aspx, it explicitly says that raw_name() specifically returns the mangled ("decorated") form of the type expression. TypeIndex, with RTTI off, would not return such a string for its raw_name(). Note I have no complaint if raw_name() exists with RTTI on (and returns the mangled string), but vanishes if RTTI is off and therefore correctly breaks compilation. Regarding the problem of name() compatibility: it is deeply unfortunate that MSVC chose that name() should be demangled, while everyone else chose that name() should be mangled. It means you see this everywhere which uses type_info: #ifdef _MSC_VER ti.raw_name() #else ti.name() #endif One of the things I really like about boost::type_info is that we do away with this silliness and name() always means "the shortest unique representation string" on every platform. Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks? That way we get boost::type_info being as std::type_info ought to have been, while those who really need std::type_info to be quirky get boost::type_info_std as a direct replacement? I personally suspect that the pure unquirky boost::type_info will in fact be a more popular std::type_info replacement once authors think it through. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On Wednesday 13 November 2013 12:44:54 Niall Douglas wrote:
On 13 Nov 2013 at 14:28, Antony Polukhin wrote:
* const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled()
Looks great to me.
I like it too. Now it is a drop in replacement that supports even the MSVC extensions.
I'm afraid I disagree - you're breaking the interface contract with std::type_info when RTTI is off.
Previous commenters may not realise that template_info::name() does NOT return the same value as type_info::name() when RTTI is off. It returns an internal unique const char * value, that's all.
AFAIR, std::type_info::name() gives no guarantees of the returned string contents whatsoever. I don't see why boost::type_info::name() should offer anything more. Also, I don't think it has to return the same string with and without RTTI enabled.
My concern is that MSVC's raw_name() does something very explicit: if you read http://msdn.microsoft.com/en-us/library/vstudio/70ky2y6k.aspx, it explicitly says that raw_name() specifically returns the mangled ("decorated") form of the type expression. TypeIndex, with RTTI off, would not return such a string for its raw_name().
I do not see why boost::type_info::raw_name() should have semantics equivalent to MSVC std::type_info::raw_name(), especially since the latter is non- standard. We can implement boost::type_info::raw_name() in terms of MSVC std::type_info::raw_name(), but we surely cannot guarantee that it will always return what MSVC std::type_info::raw_name() does, on other compilers. This is the reason I objected against name_demangled() naming. In my view, boost::type_info::raw_name() should be described as a function returning an implementation-defined string that may be equivalent to boost::type_info::name() but, if possible, may be in a platform-specific mangled format. FWIW, boost::type_info interface description should allow to implement name(), raw_name() and pretty_name() all the same way - based on std::type_info::name() or another adequate source of strings in the lack of native RTTI.
Regarding the problem of name() compatibility: it is deeply unfortunate that MSVC chose that name() should be demangled, while everyone else chose that name() should be mangled. It means you see this everywhere which uses type_info:
#ifdef _MSC_VER ti.raw_name() #else ti.name() #endif
A little irrelevant, but I personally don't think MSVC choice was wrong. I'd prefer std::type_info::name() to return a human readable string on most compilers instead of having to write hacks like __cxa_demangle().
One of the things I really like about boost::type_info is that we do away with this silliness and name() always means "the shortest unique representation string" on every platform.
Again, std::type_info::name() does not have that meaning and there is no reason for boost::type_info::name() to have it. boost::type_info::name() should be exactly what it advertises itself - an equivalent for std::type_info::name(). For any other preference you should be using boost::type_info::raw_name() or boost::type_info::pretty_name().
Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks?
I don't see the point in such duplication. boost::type_index will only work with boost::type_info anyway.

On 13 Nov 2013 at 22:46, Andrey Semashev wrote:
Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks?
I don't see the point in such duplication. boost::type_index will only work with boost::type_info anyway.
There are two primary use cases for boost::type_info: (i) as a better (static) std::type_info (ii) as a direct std::type_info substitute working with RTTI off. What boost::type_info does not currently provide which std::type_info does is a method of retrieving the type mangling string with RTTI off. It could be easily added if name() can return a std::string, but that is outside the scope of this peer review. Those use cases are not identical. I also don't see why my proposal to provide both type_info replacements has anything to do with your arguments which appear to mostly be based on API purity rather than practical concerns. I proposed that boost::type_info be pure and fitting your stated wishes, while a new boost::type_info_std (which is implicitly convertible to a boost::type_info) is quirky. You get what you want, while people wanting a direct drop in perfect substitute for std::type_info also get what they want. Trying to get boost::type_info to on its own be everything to everybody I don't think is wise because the use cases are semantically distinct. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On Wednesday 13 November 2013 14:29:07 Niall Douglas wrote:
On 13 Nov 2013 at 22:46, Andrey Semashev wrote:
Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks?
I don't see the point in such duplication. boost::type_index will only work with boost::type_info anyway.
There are two primary use cases for boost::type_info: (i) as a better (static) std::type_info (ii) as a direct std::type_info substitute working with RTTI off.
What boost::type_info does not currently provide which std::type_info does is a method of retrieving the type mangling string with RTTI off. It could be easily added if name() can return a std::string, but that is outside the scope of this peer review.
Those use cases are not identical.
Yes, but they also are not exclusive. At least, not with respect to name functions.
I also don't see why my proposal to provide both type_info replacements has anything to do with your arguments which appear to mostly be based on API purity rather than practical concerns. I proposed that boost::type_info be pure and fitting your stated wishes, while a new boost::type_info_std (which is implicitly convertible to a boost::type_info) is quirky. You get what you want, while people wanting a direct drop in perfect substitute for std::type_info also get what they want. Trying to get boost::type_info to on its own be everything to everybody I don't think is wise because the use cases are semantically distinct.
I don't like the idea of having two practically equivalent classes which basically do the same thing. The difference between the classes would be in the behavior, which is not specified by the standard in the first place and can be adjusted in a non-breaking manner in a unified boost::type_info class.

On 14 Nov 2013 at 0:04, Andrey Semashev wrote:
I don't like the idea of having two practically equivalent classes which basically do the same thing. The difference between the classes would be in the behavior, which is not specified by the standard in the first place and can be adjusted in a non-breaking manner in a unified boost::type_info class.
Taking off my peer review manager hat: I see there being a base boost::type_info class, with quirks adapters for backwards compatibility deriving from it. Such quirk adapters would be extremely thin (basically changing what name() does, and a few other minor changes). Regarding the standard's definition of type_info, that is unimportant here except where some boost::type_info_something is declared to behave exactly like std::type_info. If we explicitly declare that boost::type_info is intended as being superior to the standard and therefore a breaking change from it, I see no issue. Someone will now mention that because boost::type_info derives from std::type_info that one cannot safely change its API. And this was exactly my original point: a boost::type_info_something capable of directly substituting according to the C++ type rules for std::type_info MUST replicate as a minimum what the C++11 standard says AND what the local implementation std::type_info does, including quirks. Otherwise you get the problem that one compiland using std::type_info will segfault when it encounters a boost::type_info from another compiland which has been auto-converted to std::type_info by the compiler. Quite separately from this is where the programmer intentionally replaces std::type_info with boost::type_info and the program compiles and executes correctly because boost::type_info has been cleverly designed to do so AND the programmer understands what that means. That's a compile-time compatible type_info, which is very different from a run-time compatible type_info. Putting back on my peer review manager hat, I'd like to thank the list for such a useful debate. It's certainly helped me see aspects of the library I had not previously considered. I'll try to produce an interim report this weekend to help frame the discussion during the last five days of review. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

2013/11/13 Andrey Semashev
On Wednesday 13 November 2013 12:44:54 Niall Douglas wrote:
Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks?
I don't see the point in such duplication. boost::type_index will only work with boost::type_info anyway.
boost::type_index and std::type_info can be compared with each other. boost::type_info is derived from std::type_info and it can be used in any method that accepts std::type_info. Let me put the question in other way: do we want to support MS extensions? If yes, then advantages are: * less user code will be broken during conversion for std:;type_info to boost::type_info (see for example boost::any::type()) Disadvantages: * supporting vendor specific extensions is a bad practice * we loose the meaning of name() as a "fast short nonreadable name" and get something indeterminated instead * more functions => more fuss for the user * calls to name() will become slower on MS Windows Let's change the balance in a following way (NEW WAY): * const char* name() // same as std::type_info::raw_name() * const char* raw_name() // // same as std::type_info::raw_name() * std::string pretty_name() // was name_demangled() Now we have following advantages: * less user code will be broken during conversion for std::type_info to boost::type_info (see for example boost::any::type()) * we do not loose the meaning of name() as a "fast short nonreadable name" and do not get indeterminated faunctions instead * calls to name() are fast Disadvantages: * supporting vendor specific extensions is a bad practice * more functions => more fuss for the user * calls to name() on MSVC will return different result (however name() may return whatever it whants, according to Standard) But do we *really* want to encourage users that write unportable code? -- Best regards, Antony Polukhin

On 14/11/2013 09:17, Quoth Antony Polukhin:
* we loose the meaning of name() as a "fast short nonreadable name" and get something indeterminated instead
Where is that meaning assigned? I don't believe the standard specifies what form the return value will take, just that it's some unique string literal.

On 14 Nov 2013 at 10:49, Gavin Lambert wrote:
* we loose the meaning of name() as a "fast short nonreadable name" and get something indeterminated instead
Where is that meaning assigned? I don't believe the standard specifies what form the return value will take, just that it's some unique string literal.
That description of its meaning came from me, so I'll answer this: it isn't defined by the standard to be that, but it IS defined by common idiomatic usage to be so. Any type registry in Boost I've seen appears to use name() (or raw_name() if _MSC_VER) as being the least cost way of obtaining a unique string identifier for some type specification. Certainly Antony has striven to duplicate that idiom by avoiding the use of malloc in name(), and hence on pre-C++11 compilers TypeIndex cannot return a string which is identical to what is returned by name() (or raw_name() if _MSC_VER) with std::type_info. I personally think there is a separate use case for both situations i.e. a standards compliant name() which isn't ABI compliant but is equally low cost, and a perfect RTTI-disabled substitute exactly replicating name() but with the cost of fire and forget mallocs - the only thing needing this is code which needs the mangling specifically, or code which needs RTTI disabled code to work perfectly with RTTI enabled code e.g. code which stores name() to persistent storage. For me personally that would imply extra adapters adding such extra functionality if and only if there is sufficient demand for it, but we'll see how things look at the end of peer review. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On 15/11/2013 09:26, Quoth Niall Douglas:
That description of its meaning came from me, so I'll answer this: it isn't defined by the standard to be that, but it IS defined by common idiomatic usage to be so. Any type registry in Boost I've seen appears to use name() (or raw_name() if _MSC_VER) as being the least cost way of obtaining a unique string identifier for some type specification.
Well, thus far when using type_info as an index into a collection I use only its type_info* value (as this is guaranteed by the standard to be unique per type but constant across multiple invocations of typeid on the same type of object), and name() is only used to print a human readable name (via MSVC) for diagnostic purposes (since the standard does NOT guarantee that the string value be unique, unlike the pointer, it's not really suitable for use as a key -- although granted most of the time you can get away with it). It's also faster. :) I don't know if this usage is more typical than yours or not, or how hard it is to emulate this with a non-compiler-supported library, but it's something that would have to be considered if the library is intended to be a drop-in replacement for existing code.
Certainly Antony has striven to duplicate that idiom by avoiding the use of malloc in name(), and hence on pre-C++11 compilers TypeIndex cannot return a string which is identical to what is returned by name() (or raw_name() if _MSC_VER) with std::type_info. I personally think there is a separate use case for both situations i.e. a standards compliant name() which isn't ABI compliant but is equally low cost, and a perfect RTTI-disabled substitute exactly replicating name() but with the cost of fire and forget mallocs - the only thing needing this is code which needs the mangling specifically, or code which needs RTTI disabled code to work perfectly with RTTI enabled code e.g. code which stores name() to persistent storage.
I think that at a minimum if RTTI is enabled then boost::type_info::name() must return exactly what std::type_info::name() would, on that platform. (This is still "least cost" since it'd just be passing the return value through without modification.) It should be free to add additional methods (such as raw_name or short_name or long_name or whatever) that can do whatever, including memory allocation and returning temporary values, but as long as drop-in-replacement is a goal it can't be allowed to change the behaviour of name() itself. When RTTI is disabled, of course, it has more freedom in the actual returned value because the standard name() doesn't exist. But it still must be able to return a const char* that has static lifetime, because people are expecting that from the RTTI-enabled case. (In particular, it must be legal to call name() on a temporary and use the returned value as a bare const char* at any later point in the code, even once the temporary is out of scope.) If the library is intended to be an alternative implementation that is *not* a drop-in replacement, then some of these strictures could be relaxed a bit (and it shouldn't inherit from std::type_info any more).

On 15 Nov 2013 at 10:51, Gavin Lambert wrote:
Well, thus far when using type_info as an index into a collection I use only its type_info* value (as this is guaranteed by the standard to be unique per type but constant across multiple invocations of typeid on the same type of object), and name() is only used to print a human readable name (via MSVC) for diagnostic purposes (since the standard does NOT guarantee that the string value be unique, unlike the pointer, it's not really suitable for use as a key -- although granted most of the time you can get away with it). It's also faster. :)
Unfortunately typeid() does NOT necessarily return the same type_info instance for some type if done across DLL or shared object boundaries. This is because the compiler generates static type_info instances only for those types where typeid() is used (with weak or selectany linkage), and the linker links them up as if they were any ordinary structure instance. That means a copy per DLL/SO. The workaround is to use the mangled type specification, and to do a string comparison to match them. That works very well, so long as you are using the same compiler. In my own code I have even dumped the mangled form to disc as an easy type identifying string id for an on-disc type database (expect more of this coming for my C++ Now 2014 presentation if it is accepted!). Due to these interop problems Antony's TypeIndex does string comparisons as well. It's the only reliable way I believe.
I think that at a minimum if RTTI is enabled then boost::type_info::name() must return exactly what std::type_info::name() would, on that platform. (This is still "least cost" since it'd just be passing the return value through without modification.)
Me personally I'd prefer name() to always return the mangled name on every platform so it's portable and consistent. Unless one is using a quirks type shim not called boost::type_info. Remember that boost::type_info is not intended to be an exact replacement for std::type_info. It is expected that Boost code using std::type_info will need "porting" to boost::type_info. Antony has provided all the necessary patches required for many Boost libraries.
It should be free to add additional methods (such as raw_name or short_name or long_name or whatever) that can do whatever, including memory allocation and returning temporary values, but as long as drop-in-replacement is a goal it can't be allowed to change the behaviour of name() itself.
Again, it's not intended to be a perfect drop in. I do see Steven's point about it accidentally becoming treated by the compiler as a perfect drop in due to type slicing. How serious that is is something I'll need to consider.
When RTTI is disabled, of course, it has more freedom in the actual returned value because the standard name() doesn't exist. But it still must be able to return a const char* that has static lifetime, because people are expecting that from the RTTI-enabled case. (In particular, it must be legal to call name() on a temporary and use the returned value as a bare const char* at any later point in the code, even once the temporary is out of scope.)
On non-MSVC compilers, merely the attempt to access or create a type_info would generally cause a compiler error if RTTI is disabled. I therefore think that in this use case boost::type_info can merrily do whatever it feels like, with any API definition it feels like including returning std::string from name(). After all, the code didn't compile at all before, so no backwards compatibility is needed here - if it compiles at all and no semantics are broken, who cares? On MSVC, typeid() works just fine as does type_info if RTTI is disabled. It's just that typeid() can no longer cope with polymorphism and the compiler warns if you try to use typeid with a polymorphic type. Here things are tougher if and only if there is Boost code written to work on MSVC with RTTI off. I don't believe there is any such code in Boost, and therefore this is also a non-issue.
If the library is intended to be an alternative implementation that is *not* a drop-in replacement, then some of these strictures could be relaxed a bit (and it shouldn't inherit from std::type_info any more).
My overwhelming concern with boost::type_info is whether the present implementation will cause surprises. Antony has already done a lot of work to remove a lot of surprises by generating warnings or static assertion failures. I need to ponder more deeply the concern about undefined behaviour during a type slicing cast vs having it act as a proxy to a const std::type_info & supplied via a constructor. It'll take me a few days to ponder this I think. The latter is not undefined behaviour, but do you actually gain anything in practice? Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On 15/11/2013 12:11, Quoth Niall Douglas:
Unfortunately typeid() does NOT necessarily return the same type_info instance for some type if done across DLL or shared object boundaries. This is because the compiler generates static type_info instances only for those types where typeid() is used (with weak or selectany linkage), and the linker links them up as if they were any ordinary structure instance. That means a copy per DLL/SO.
True, but how often does generation and comparison of a typeid actually need to cross DLL/SO boundaries? (Storage might, but generally that's just as an opaque value.) Typically usage would either be fairly localised or would be in templates -- and while it's possible to export and import templates across DLL/SO boundaries, it's usually not actually done. Granted I'm coming at this mostly from an application perspective, so I am probably unaware of exactly how Boost libraries want to use these.
Me personally I'd prefer name() to always return the mangled name on every platform so it's portable and consistent. Unless one is using a quirks type shim not called boost::type_info.
I kind of see that the other way around -- if you want to call something "type_info", then it ought to behave as close as possible like the standard "type_info" (albeit with some extras). If you want different behaviour you should give it a different name. :)
Remember that boost::type_info is not intended to be an exact replacement for std::type_info. It is expected that Boost code using std::type_info will need "porting" to boost::type_info. Antony has provided all the necessary patches required for many Boost libraries.
I have received the opposite impression from discussion thus far. Perhaps I have misinterpreted something.
On non-MSVC compilers, merely the attempt to access or create a type_info would generally cause a compiler error if RTTI is disabled. I therefore think that in this use case boost::type_info can merrily do whatever it feels like, with any API definition it feels like including returning std::string from name(). After all, the code didn't compile at all before, so no backwards compatibility is needed here - if it compiles at all and no semantics are broken, who cares?
I didn't mean it quite like that. I meant that people might be approaching this as "here's some code that works with standard RTTI", "here's a library that emulates typeid with RTTI disabled", "let's just plug them in!". Granted that the actual results may vary (different strings returned, not able to get the dynamic type without RTTI), but these seem like "unsurprising" sorts of changes. typeid also makes certain guarantees about lifetime that existing user code would be assuming, and might be surprised if these are not met. Again, if it's not being positioned as a drop-in then it's less of an issue (but means more user code might need to be changed). But then if it's not being positioned as a drop-in then I don't know why it's derived from std::type_info and doing the casts the way it is. Maybe there's some other reason for that?

On 15 Nov 2013 at 13:44, Gavin Lambert wrote:
True, but how often does generation and comparison of a typeid actually need to cross DLL/SO boundaries? (Storage might, but generally that's just as an opaque value.) Typically usage would either be fairly localised or would be in templates -- and while it's possible to export and import templates across DLL/SO boundaries, it's usually not actually done.
I beg to differ! A classic example is Boost.Python where more than one Python extension DLL module is loaded, both with a dependency to the same Boost.Python DLL instance. Boost.Python's type registries correctly store and compare mangled strings to cope with this quite common situation.
Me personally I'd prefer name() to always return the mangled name on every platform so it's portable and consistent. Unless one is using a quirks type shim not called boost::type_info.
I kind of see that the other way around -- if you want to call something "type_info", then it ought to behave as close as possible like the standard "type_info" (albeit with some extras). If you want different behaviour you should give it a different name. :)
Yes and no. There is semantic equivalence, API equivalence and ABI equivalence. They're all not necessarily the same thing. I personally don't mind a type_info which fixes the mistakes in the standard type_info if it causes the compiler to puke instead of hidden misoperation. There is something to be said for eliminating the name() function altogether actually as its meaning is too vague and non-portable. Removing it in boost::type_info guarantees that the porting effort makes the author choose exactly what they mean with all the runtime costs implied (e.g. a demangled type string is usually run time calculated and longer than a mangled type string).
Remember that boost::type_info is not intended to be an exact replacement for std::type_info. It is expected that Boost code using std::type_info will need "porting" to boost::type_info. Antony has provided all the necessary patches required for many Boost libraries.
I have received the opposite impression from discussion thus far. Perhaps I have misinterpreted something.
People jumped in with their particular preferred angles, as is normal during peer review. Also as is normal during peer review the relevance of the discussion to the library being reviewed can become quite tenuous. In this situation we've had a very good, and very useful (to me as the review manager) discussion. It helps hugely the library is so small and single purpose.
Again, if it's not being positioned as a drop-in then it's less of an issue (but means more user code might need to be changed). But then if it's not being positioned as a drop-in then I don't know why it's derived from std::type_info and doing the casts the way it is. Maybe there's some other reason for that?
Antony was trying to save on code bloat, amongst other things. The UB based implementation had the huge benefit of zero bloat with RTTI on. I think unfortunately considering the rationale I gave in a previous message we probably can't go with that, it's too UB due to the virtual function table mismatch. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

There is something to be said for eliminating the name() function altogether ...
Yes, first determine what types of name functions you want (mangled, demangled, compatible, unique, etc). Then supply ALL those functions. If one of them is called 'name()' and the class derives from std::type_info, then probably it should return the same as the std one. If lots of existing code is calling name()-but-raw_name()-on-MSVC then find out what *meaning* they are giving the function, and supply that. ie fast_unique_name() or whatever best describes the requirements. But first determine the requirements (based on how std::ype_info::name() et al is used in existing code). Tony

On 22 Nov 2013 at 18:28, Gottlob Frege wrote:
There is something to be said for eliminating the name() function altogether ...
Yes, first determine what types of name functions you want (mangled, demangled, compatible, unique, etc). Then supply ALL those functions.
Indeed, this is what I suggested to Antony off-list: /*! Returns a static const char string of unknown format uniquely identifying this type. The only guarantee is that this string will be unique to the type within this process lifetime.*/ const char *unique_name() const noexcept; /*! Returns a representation of this type suitable for printing. This call may take some time as its storage may not be cached.*/ std::string pretty_name() const; class enum mangling { Native, //!< Whatever the native mangling used by this toolset is MSVC, //!< The Microsoft C++ mangling format Itanium //!< The Itanium C++ mangling format }; /*! Returns the mangled form of the string representation of the type. After the calculation the value is cached statically such that the c_str() function can be used to convert the returned string to a const char * format identical to what may be returned by std::type_info::name() (or raw_name() on MSVC). This function may throw an exception if it does not support mangled type string calculation, including when mangling=Native on some platforms.*/ const std::string &mangled_name(mangling=Native) const; Note I have not convinced Antony of the merit of this approach (i.e. of not providing a name() function at all, and leaving it up to user code to subclass boost::type_index if so desired with something which does implement some name() function locally to that specific library). Thanks for the feedback Tony, and I hope things at our former employer aren't too bad. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On 25/11/2013 10:06, Quoth Niall Douglas:
class enum mangling { Native, //!< Whatever the native mangling used by this toolset is MSVC, //!< The Microsoft C++ mangling format Itanium //!< The Itanium C++ mangling format };
/*! Returns the mangled form of the string representation of the type. After the calculation the value is cached statically such that the c_str() function can be used to convert the returned string to a const char * format identical to what may be returned by std::type_info::name() (or raw_name() on MSVC). This function may throw an exception if it does not support mangled type string calculation, including when mangling=Native on some platforms.*/
const std::string &mangled_name(mangling=Native) const;
Given that I'm still mostly using not-C++11 compilers I get a little nervous when I see "class enum"s. Not that this is a reason to not do it. :) I'm not sure what the motivation for having the returned mangled type configurable is though. Presumably most existing use cases would just want Native, and the burden of providing alternates might be significant (and therefore left unimplemented and throwing an exception, as specified, limiting the potential usefulness of this anyway). Though as I've said before I admit to ignorance about many of the use cases, so maybe there is a need for this that I am unaware of. Why not just specify a mangled_name that will return the native mangled name if it can, but is allowed to return the same as unique_name? Or is that too close to what unique_name itself will do? (One use case I can imagine for a specified format is for cross-compiler/machine serialisation, but OTOH I'm not sure how much I'd want to trust using a mangled name for that anyway. Maybe I'm overly paranoid though.)

On 25 Nov 2013 at 12:23, Gavin Lambert wrote:
Given that I'm still mostly using not-C++11 compilers I get a little nervous when I see "class enum"s. Not that this is a reason to not do it. :)
Oh sure, the code I wrote was purely for illustration. It would get wrapped in the appropriate Boost class enum macro magic in practice.
I'm not sure what the motivation for having the returned mangled type configurable is though. Presumably most existing use cases would just want Native, and the burden of providing alternates might be significant (and therefore left unimplemented and throwing an exception, as specified, limiting the potential usefulness of this anyway). Though as I've said before I admit to ignorance about many of the use cases, so maybe there is a need for this that I am unaware of.
You're right I should have explained this much better. There is a need for a truly portable type specification string such that code from GCC can work with code from MSVC and so on where the type string is being kept in storage. Antony wants to (much later on) add a custom type mangling scheme to TypeIndex which would be universal and absolutely as compact as possible (symbol mangling schemes are designed to be fast rather than compact). I simply had the class enum in there to facilitate such an extension later. (Also, I think it very possible that clang might one day let you generate any mangling scheme you like, so I didn't want to rule that out).
Why not just specify a mangled_name that will return the native mangled name if it can, but is allowed to return the same as unique_name? Or is that too close to what unique_name itself will do?
mangled_name() here is *guaranteed* to return exactly what std::type_info does, even if RTTI is turned off. I would expect such a facility to be highly useful for where boost::type_index binaries might be mixed with std::type_info binaries and you need to compare a type_index indexed type with a std::type_info indexed type. Also, of course, sometimes you really do want the exact symbol mangling to be returned because you're going to parse that mangling into a AST, and use that AST to auto-generate yourself some LLVM :). Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On 25/11/2013 13:42, Quoth Niall Douglas:
mangled_name() here is *guaranteed* to return exactly what std::type_info does, even if RTTI is turned off. I would expect such a facility to be highly useful for where boost::type_index binaries might be mixed with std::type_info binaries and you need to compare a type_index indexed type with a std::type_info indexed type. Also, of course, sometimes you really do want the exact symbol mangling to be returned because you're going to parse that mangling into a AST, and use that AST to auto-generate yourself some LLVM :).
Ah, I see. That would indeed be useful, provided it doesn't involve too many shenanigans to implement. ;)

AMDG On 11/13/2013 12:17 PM, Antony Polukhin wrote:
2013/11/13 Andrey Semashev
On Wednesday 13 November 2013 12:44:54 Niall Douglas wrote:
Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks?
I don't see the point in such duplication. boost::type_index will only work with boost::type_info anyway.
boost::type_index and std::type_info can be compared with each other. boost::type_info is derived from std::type_info and it can be used in any method that accepts std::type_info.
<snip>
Let's change the balance in a following way (NEW WAY): * const char* name() // same as std::type_info::raw_name() * const char* raw_name() // // same as std::type_info::raw_name() * std::string pretty_name() // was name_demangled()
As far as I am concerned, boost::type_info::name *must* return the same value as std::type_info::name. You have to expect that use of boost::type_info will be mixed with std::type_info. It's unreasonable to expect everything to use boost::type_info, and if the behavior is different, it *will* cause surprises. You could perhaps make a case for different behavior if boost::type_info were completely separate, but since boost::type_info inherits from std::type_info, there's absolutely no excuse. In Christ, Steven Watanabe

2013/11/13 Niall Douglas
On 13 Nov 2013 at 14:28, Antony Polukhin wrote:
* const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled()
Looks great to me.
I like it too. Now it is a drop in replacement that supports even the MSVC extensions.
I'm afraid I disagree - you're breaking the interface contract with std::type_info when RTTI is off.
Previous commenters may not realise that template_info::name() does NOT return the same value as type_info::name() when RTTI is off. It returns an internal unique const char * value, that's all.
Well, actually current implementation does return the same value. MSVC allows to use typeinfo for Types even with RTTI disabled, so it is possible to do so.
Can I suggest this instead: instead of making boost::type_info more like the flawed std::type_info, can you leave boost::type_info to be pure and instead add a new boost::type_info_std or something which does replicate std::type_info's implementation specific quirks?
That way we get boost::type_info being as std::type_info ought to have been, while those who really need std::type_info to be quirky get boost::type_info_std as a direct replacement? I personally suspect that the pure unquirky boost::type_info will in fact be a more popular std::type_info replacement once authors think it through.
I do not think that multiplying entities is good. It's better to have a single class that suits (almost) all the situations. -- Best regards, Antony Polukhin

On 13/11/2013 23:16, Quoth Antony Polukhin:
* const char* name() // same as std::type_info::name() * const char* raw_name() // mangled/short/not very readable name * std::string pretty_name() // was name_demangled()
That'd be ok, but the reason why I suggested "short" and "long" rather than "raw" and "pretty" is that even "raw" and "pretty" make implications that we might not follow (eg. with RTTI off, all three will return the same value, which might be neither raw nor pretty, but is at least relatively both short and long if it's the only possible name). (And a future extension might be an "even prettier name" that tries to remove leading "struct" etc.) Also, earlier in the thread you dismissed the idea of storing a string buffer within the type_info, but I'm wondering if that might not be a good idea after all. If type_info is permitted to contain std::string members that are initially empty but populated on first call to their corresponding name function, then repeated calls to the same name function would only pay any demangling/parsing cost on the first call. It won't make any difference in the direct typeid rvalue->name case, but if code is keeping a type_info instance around (eg. as a key in a container) it seems reasonable to assume that one of the name methods might get called more than once. Slight downside is the extra size of the type_info (particularly in the case where it is used without ever asking for the name), but I don't think this is too onerous. It's tempting to also make all the methods return "const char *" (to possibly save on copies) if we have member strings to return them from, but this is still potentially dangerous if the user assumes the string has static lifetime when called on a temporary type_info (which is probably a common pattern for the drop-in-replacement case). On the other hand, the drop-in-replacement probably wouldn't be calling pretty_name/long_name so it might not matter; we'd just need to document that the return value should immediately be saved to a std::string if called on a temporary type_info, or that the type_info should be kept around longer. (This would be adding a copy in the temporary case to save copies in the repeated-call case though. I'm not sure which direction would be better to optimise towards.)

AMDG On 11/12/2013 11:34 AM, Niall Douglas wrote:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes:
1. Should this library be accepted into Boost?
No. This library should not be accepted into Boost
in its current form.
type_info.hpp:139:
return static_cast

2013/11/14 Steven Watanabe
AMDG
On 11/12/2013 11:34 AM, Niall Douglas wrote:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes:
1. Should this library be accepted into Boost?
No. This library should not be accepted into Boost in its current form.
type_info.hpp:139: return static_cast
(typeid(type)); This is undefined behavior, and there is no way to make it correct.
This is a necessary evil and it is harmless: * all the methods of std::type_info (except destructor) are non virtual, so for example calls to name() will call boost::type_info::name() * it is *undefined* which destructor (std::type_info or boost::type_info) will be called *but*: * boost::type_info contains no members, it's size must be equal to the size of std::type_info, so no harm if boost::type_info destructor won't be called * destructor of std::type_info will be called anyway I can add assert to tests to ensure that sizeof(std::type_info) == sizeof(boost::type_info). -- Best regards, Antony Polukhin

On Thu, Nov 14, 2013 at 9:26 AM, Antony Polukhin
2013/11/14 Steven Watanabe
AMDG
On 11/12/2013 11:34 AM, Niall Douglas wrote:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes:
1. Should this library be accepted into Boost?
No. This library should not be accepted into Boost in its current form.
type_info.hpp:139: return static_cast
(typeid(type)); This is undefined behavior, and there is no way to make it correct.
This is a necessary evil and it is harmless: * all the methods of std::type_info (except destructor) are non virtual, so for example calls to name() will call boost::type_info::name() * it is *undefined* which destructor (std::type_info or boost::type_info) will be called *but*: * boost::type_info contains no members, it's size must be equal to the size of std::type_info, so no harm if boost::type_info destructor won't be called * destructor of std::type_info will be called anyway
I can add assert to tests to ensure that sizeof(std::type_info) == sizeof(boost::type_info).
I think the undefined behavior can be removed with the following trick:
1. boost::type_info should not derive from std::type_info (it would
have no base classes or data members). Its destructor should be
deleted, as well as its constructors and assignment.
2. The above cast should be replaced with reinterpret_cast:
return reinterpret_cast

2013/11/14 Andrey Semashev
On Thu, Nov 14, 2013 at 9:26 AM, Antony Polukhin
wrote: 2013/11/14 Steven Watanabe
AMDG
On 11/12/2013 11:34 AM, Niall Douglas wrote:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes:
1. Should this library be accepted into Boost?
No. This library should not be accepted into Boost in its current form.
type_info.hpp:139: return static_cast
(typeid(type)); This is undefined behavior, and there is no way to make it correct.
This is a necessary evil and it is harmless: * all the methods of std::type_info (except destructor) are non virtual, so for example calls to name() will call boost::type_info::name() * it is *undefined* which destructor (std::type_info or boost::type_info) will be called *but*: * boost::type_info contains no members, it's size must be equal to the size of std::type_info, so no harm if boost::type_info destructor won't be called * destructor of std::type_info will be called anyway
I can add assert to tests to ensure that sizeof(std::type_info) == sizeof(boost::type_info).
I think the undefined behavior can be removed with the following trick:
1. boost::type_info should not derive from std::type_info (it would have no base classes or data members). Its destructor should be deleted, as well as its constructors and assignment. 2. The above cast should be replaced with reinterpret_cast:
return reinterpret_cast
(typeid(type)); 3. All methods of boost::type_info should perform the reverse reinterpret_cast of *this before accessing std::type_info.
The standard warrants that such two-way casting would yield the original reference to std::type_info.
However, this turns out to be quite a lot of hackery and makes me wonder if boost::type_info is needed at all. Why not just have boost::type_index that will work directly with std::type_info?
Unfortunately, boost::type_info must derive from std::type_info for compatibility reasons. Without it the following code won't compile: std::type_index ti = boost:type_id<int>(); This may look like a rare case, however will be quite common if other Boost libraries adopt the TypeIndex. Is my favorite example with Boost.Any: boost::any a = 10; // Imagine that Boost.Any uses boost:;type_info instead of std::type_info class_that_constructs_from_std_type_info = a.type(); // operator const std::type_info&() won't help std::type_index ti = a.type(); In v1.0 of TypeIndex library there was no boost::type_info, there was only boost::type_index. version 2 was started because v1.0 was hard to use in existing Boost libraries that that return std::type_info to the user. Version 1.0 is not a drop-in replacement. It can be used only if we have full control over the code that uses it. Why there is a such need in drop-in replacement? Here are the reasons: * some compilers fail to compare std::type_info across modules (surprise!) * some libraries fail to write a sane hashing function for std::type_info * users want to use Boost without RTTI and fail: http://stackoverflow.com/questions/14557313/is-it-possible-to-use-boost-prog... Here are some more issues in Boost: * there is a mess with stripping/not stripping const, volatile, reference * there is a mess with name() calls, plenty of places where name() used for debug/user output without demangling * some of the Boost libraries demangle names by themselfs and forget to dealocate memory (at least valgrind says so) In three words: std::type_info is broken. There is a need to give users an ability to write portable code, but do not break existing users code (that do fail on some compilers). There is a need to put all the std::type_info workarounds all around the Boost in s single place, which will be easy to maintain. It is not good to see in different libraries code like that: // Borrowed from Boost.Python library: determines the cases where we // need to use std::type_info::name to compare instead of operator==. #if defined( BOOST_NO_TYPEID ) # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) #elif (defined(__GNUC__) && __GNUC__ >= 3) \ || defined(_AIX) \ || ( defined(__sgi) && defined(__host_mips)) # include <cstring> # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \ (std::strcmp((X).name(),(Y).name()) == 0) # else # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) #endif Or like this: // See boost/python/type_id.hpp // TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp # if (defined(__GNUC__) && __GNUC__ >= 3) \ || defined(_AIX) \ || ( defined(__sgi) && defined(__host_mips)) \ || (defined(__hpux) && defined(__HP_aCC)) \ || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) # define BOOST_AUX_ANY_TYPE_ID_NAME #include <cstring> # endif Did you note that macro *differ*? And by the way, in both cases it is not optimal! -- Best regards, Antony Polukhin

On Thu, Nov 14, 2013 at 11:48 AM, Antony Polukhin
Unfortunately, boost::type_info must derive from std::type_info for compatibility reasons. Without it the following code won't compile:
std::type_index ti = boost:type_id<int>();
This may look like a rare case, however will be quite common if other Boost libraries adopt the TypeIndex.
I think the above need not to work. After all, you don't expect this to work: std::shared_ptr< int > p = boost::make_shared< int >(10); It should be no problem with sticking to boost::type_index and boost::type_id in Boost libraries, and for user's code we could provide means to convert between boost::type_index and std::type_index.
Is my favorite example with Boost.Any:
boost::any a = 10;
// Imagine that Boost.Any uses boost:;type_info instead of std::type_info class_that_constructs_from_std_type_info = a.type();
// operator const std::type_info&() won't help std::type_index ti = a.type();
Boost.Any can use boost::type_index internally and a.type() can still return std::type_info const& for backward compatibility. We just need a method such as this: std::type_info const& boost::type_index::get() const;
Why there is a such need in drop-in replacement? Here are the reasons:
* some compilers fail to compare std::type_info across modules (surprise!) * some libraries fail to write a sane hashing function for std::type_info * users want to use Boost without RTTI and fail: http://stackoverflow.com/questions/14557313/is-it-possible-to-use-boost-prog...
Here are some more issues in Boost: * there is a mess with stripping/not stripping const, volatile, reference * there is a mess with name() calls, plenty of places where name() used for debug/user output without demangling * some of the Boost libraries demangle names by themselfs and forget to dealocate memory (at least valgrind says so)
In three words: std::type_info is broken.
I think that these problems can be tackled by just having boost::type_index and boost::type_id. boost::type_index can implement the name functions we discussed and offer interfacing with std::type_info and implement workarounds for its bugs. boost::type_id (or preferably its variations) can solve problems with cv-qualification, references and visibility by wrapping the type before constructing boost::type_index. The only reason for boost::type_info I see is to emulate RTTI when it's disabled. But as I see in the code, it is just an alias for template_info in this case. So perhaps we should just make it that - an alias to std::type_info or boost::template_info, depending on the configuration. This way it will just allow to use the type_info type portably, without preprocessor checks everywhere.

2013/11/14 Andrey Semashev
On Thu, Nov 14, 2013 at 11:48 AM, Antony Polukhin
wrote: Unfortunately, boost::type_info must derive from std::type_info for compatibility reasons. Without it the following code won't compile:
std::type_index ti = boost:type_id<int>();
This may look like a rare case, however will be quite common if other
Boost
libraries adopt the TypeIndex.
I think the above need not to work. After all, you don't expect this to work:
std::shared_ptr< int > p = boost::make_shared< int >(10);
It should be no problem with sticking to boost::type_index and boost::type_id in Boost libraries, and for user's code we could provide means to convert between boost::type_index and std::type_index.
Is my favorite example with Boost.Any:
boost::any a = 10;
// Imagine that Boost.Any uses boost:;type_info instead of std::type_info class_that_constructs_from_std_type_info = a.type();
// operator const std::type_info&() won't help std::type_index ti = a.type();
Boost.Any can use boost::type_index internally and a.type() can still return std::type_info const& for backward compatibility. We just need a method such as this:
std::type_info const& boost::type_index::get() const;
Why there is a such need in drop-in replacement? Here are the reasons:
* some compilers fail to compare std::type_info across modules (surprise!) * some libraries fail to write a sane hashing function for std::type_info * users want to use Boost without RTTI and fail:
http://stackoverflow.com/questions/14557313/is-it-possible-to-use-boost-prog...
Here are some more issues in Boost: * there is a mess with stripping/not stripping const, volatile, reference * there is a mess with name() calls, plenty of places where name() used
for
debug/user output without demangling * some of the Boost libraries demangle names by themselfs and forget to dealocate memory (at least valgrind says so)
In three words: std::type_info is broken.
I think that these problems can be tackled by just having boost::type_index and boost::type_id. boost::type_index can implement the name functions we discussed and offer interfacing with std::type_info and implement workarounds for its bugs. boost::type_id (or preferably its variations) can solve problems with cv-qualification, references and visibility by wrapping the type before constructing boost::type_index.
The only reason for boost::type_info I see is to emulate RTTI when it's disabled. But as I see in the code, it is just an alias for template_info in this case. So perhaps we should just make it that - an alias to std::type_info or boost::template_info, depending on the configuration. This way it will just allow to use the type_info type portably, without preprocessor checks everywhere.
We are arguing about class type_info: public std::type_info { ...}; vs class type_info{ const std::type_info* ptr_; public: const std::type_info& get(); ... }; typedef ... std_type_info_if_exist_t; Can you explain me once more, what are the advantages of the second solution? -- Best regards, Antony Polukhin

On Thu, Nov 14, 2013 at 4:08 PM, Antony Polukhin
2013/11/14 Andrey Semashev
I think that these problems can be tackled by just having boost::type_index and boost::type_id. boost::type_index can implement the name functions we discussed and offer interfacing with std::type_info and implement workarounds for its bugs. boost::type_id (or preferably its variations) can solve problems with cv-qualification, references and visibility by wrapping the type before constructing boost::type_index.
The only reason for boost::type_info I see is to emulate RTTI when it's disabled. But as I see in the code, it is just an alias for template_info in this case. So perhaps we should just make it that - an alias to std::type_info or boost::template_info, depending on the configuration. This way it will just allow to use the type_info type portably, without preprocessor checks everywhere.
We are arguing about
class type_info: public std::type_info { ...};
vs
class type_info{ const std::type_info* ptr_; public: const std::type_info& get(); ... }; typedef ... std_type_info_if_exist_t;
Can you explain me once more, what are the advantages of the second solution?
No, I was thinking about something like this:
// type_index/type_info.hpp
namespace boost {
#if HAS_RTTI
typedef std::type_info type_info;
#else
typedef boost::template_info type_info;
#endif
}
// type_index/type_index.hpp
#include

2013/11/14 Andrey Semashev
class type_index { boost::type_info const* m_type_info;
public: explicit type_index(boost::type_info const&); boost::type_info const& get() const; // as previously discussed: const char* name() const; const char* raw_name() const; std::string pretty_name() const; };
Don't really like the "get()" name. Following name is more clear: public: boost::type_info const& type_info() const noexcept; Ok? -- Best regards, Antony Polukhin

On Friday 15 November 2013 19:51:35 Antony Polukhin wrote:
2013/11/14 Andrey Semashev
<...> class type_index {
boost::type_info const* m_type_info;
public: explicit type_index(boost::type_info const&); boost::type_info const& get() const; // as previously discussed: const char* name() const; const char* raw_name() const; std::string pretty_name() const;
};
Don't really like the "get()" name. Following name is more clear:
public: boost::type_info const& type_info() const noexcept;
Ok?
Yes, that would be fine. And another amendment. In my original pseudo-code type_id() returned type_index. It should actually be boost::type_info const&, and the function should be in type_info.hpp.

Unfortunately, boost::type_info must derive from std::type_info for compatibility reasons.
It sounds like you just want to extend the functionality of `std::type_info`. Why not make `pretty_name()` a free function that accepts `std::type_info`? Also, an additional `compare_type_info()` function could be added as well to compare types portably. Plus, it would avoid the issues with using strange hacks that border on undefined behavior.
* users want to use Boost without RTTI and fail
Additionally, `boost::type_info` could be a typedef to `std::type_info` when rtti is enabled and then to some internal type to manage type info when rtti is disabled. -- View this message in context: http://boost.2283326.n4.nabble.com/TypeIndex-Peer-review-period-for-library-... Sent from the Boost - Dev mailing list archive at Nabble.com.

2013/11/15 pfultz2
Unfortunately, boost::type_info must derive from std::type_info for compatibility reasons.
It sounds like you just want to extend the functionality of `std::type_info`. Why not make `pretty_name()` a free function that accepts `std::type_info`? Also, an additional `compare_type_info()` function could be added as well to compare types portably. Plus, it would avoid the issues with using strange hacks that border on undefined behavior.
This may be useful, thou it can be achieved in other way: boost::type_index(var.get_type_info()).pretty_name(); boost::type_index(var1.get_type_info()) == var2.get_type_info();
* users want to use Boost without RTTI and fail
Additionally, `boost::type_info` could be a typedef to `std::type_info` when rtti is enabled and then to some internal type to manage type info when rtti is disabled.
Andrey Semashev already suggested something like this: #if HAS_RTTI typedef std::type_info type_info; #else typedef boost::template_info type_info; #endif This is possibly what must be done, thanks for pointing that out once more. -- Best regards, Antony Polukhin

AMDG On 11/13/2013 09:26 PM, Antony Polukhin wrote:
2013/11/14 Steven Watanabe
On 11/12/2013 11:34 AM, Niall Douglas wrote:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes:
1. Should this library be accepted into Boost?
No. This library should not be accepted into Boost in its current form.
type_info.hpp:139: return static_cast
(typeid(type)); This is undefined behavior, and there is no way to make it correct.
This is a necessary evil and it is harmless: * all the methods of std::type_info (except destructor) are non virtual, so for example calls to name() will call boost::type_info::name() * it is *undefined* which destructor (std::type_info or boost::type_info) will be called *but*: * boost::type_info contains no members, it's size must be equal to the size of std::type_info, so no harm if boost::type_info destructor won't be called * destructor of std::type_info will be called anyway
No, it is not harmless. You cannot safely assume that undefined behavior is ever harmless, just because you can't think of anything that can go wrong. In particular, the compiler is free to make assumptions that can cause your code to miscompile with optimizations on.
I can add assert to tests to ensure that sizeof(std::type_info) == sizeof(boost::type_info).
In Christ, Steven Watanabe

On 14 Nov 2013 at 7:01, Steven Watanabe wrote:
No, it is not harmless. You cannot safely assume that undefined behavior is ever harmless, just because you can't think of anything that can go wrong. In particular, the compiler is free to make assumptions that can cause your code to miscompile with optimizations on.
For the purposes of my peer review report, can you say if you know of any misoperation which any major compiler might do in this circumstance? Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

AMDG On 11/14/2013 12:29 PM, Niall Douglas wrote:
On 14 Nov 2013 at 7:01, Steven Watanabe wrote:
No, it is not harmless. You cannot safely assume that undefined behavior is ever harmless, just because you can't think of anything that can go wrong. In particular, the compiler is free to make assumptions that can cause your code to miscompile with optimizations on.
For the purposes of my peer review report, can you say if you know of any misoperation which any major compiler might do in this circumstance?
I believe that this was a problem for Boost.Move with gcc, which does something similar. It's actually quite common for old C code that casts between different structs to fail with newer compilers. For instance, Python does not work without -fno-strict-aliasing. In Christ, Steven Watanabe

2013/11/15 Steven Watanabe
AMDG
On 11/14/2013 12:29 PM, Niall Douglas wrote:
On 14 Nov 2013 at 7:01, Steven Watanabe wrote:
No, it is not harmless. You cannot safely assume that undefined behavior is ever harmless, just because you can't think of anything that can go wrong. In particular, the compiler is free to make assumptions that can cause your code to miscompile with optimizations on.
For the purposes of my peer review report, can you say if you know of any misoperation which any major compiler might do in this circumstance?
I believe that this was a problem for Boost.Move with gcc, which does something similar. It's actually quite common for old C code that casts between different structs to fail with newer compilers. For instance, Python does not work without -fno-strict-aliasing.
Looks like I've got what are you talking about. It's an optimization in
GCC, that assumes that if there is a reference to two different types and
neither of those types is char, than those types are different in memory
(are not aliases):
void foo(int64_t& v1, int32_t& v2) {
/* GCC assumes that address of v1 is not a part of v2 adresses*/
v2 = 2;
cout << v1;
}
int64_t i64 = 1;
foo(i64, reinterpret_cast

AMDG On 11/15/2013 05:50 AM, Antony Polukhin wrote:
But this error appears only when we mutate data ( https://svn.boost.org/trac/boost/wiki/Guidelines/WarningsGuidelines search for "strict-aliasing rules")
...and can be arbitrarily broken by (unknown) future optimizations, with no recourse. We wouldn't have all the problems with strict aliasing that we do today if programmers 10 years ago hadn't made exactly the same argument that you are, now. (Sure, it's undefined behavior, but we know what the compiler actually does, so it's really okay...). In Christ, Steven Watanabe

2013/11/15 Steven Watanabe
AMDG
On 11/15/2013 05:50 AM, Antony Polukhin wrote:
But this error appears only when we mutate data ( https://svn.boost.org/trac/boost/wiki/Guidelines/WarningsGuidelinessearch for "strict-aliasing rules")
...and can be arbitrarily broken by (unknown) future optimizations, with no recourse. We wouldn't have all the problems with strict aliasing that we do today if programmers 10 years ago hadn't made exactly the same argument that you are, now. (Sure, it's undefined behavior, but we know what the compiler actually does, so it's really okay...).
You're absolutely right. I've liked the idea of "make it in a way that user won't notice a difference but typeid issues will be solved" so much, that turned a blind eye to a hack with UB. This will be fixed (possibly code from v1.0 will be taken, which had no boost::type_info and contained type_index class that had a pointer to std::type_info). Do you have other ideas of what can be fixed/improved? -- Best regards, Antony Polukhin

On 15 Nov 2013 at 19:45, Antony Polukhin wrote:
...and can be arbitrarily broken by (unknown) future optimizations, with no recourse. We wouldn't have all the problems with strict aliasing that we do today if programmers 10 years ago hadn't made exactly the same argument that you are, now. (Sure, it's undefined behavior, but we know what the compiler actually does, so it's really okay...).
You're absolutely right. I've liked the idea of "make it in a way that user won't notice a difference but typeid issues will be solved" so much, that turned a blind eye to a hack with UB.
This will be fixed (possibly code from v1.0 will be taken, which had no boost::type_info and contained type_index class that had a pointer to std::type_info).
Do you have other ideas of what can be fixed/improved?
Before you make any substantial changes here Antony, I have been busy
pondering on this UB issue and on what to recommend to the review
wizards. Here are the facts:
1. The problem code is like this:
static_cast

AMDG On 11/15/2013 01:09 PM, Niall Douglas wrote:
1. I would be happy with the static upcast if no virtual function table were in play because it's single inheritance, and static_cast provides enough safeguards (e.g. erroring if the type's inheritance tree is unknown at the point of static_cast use). It's a very common pattern in C++ code and is used throughout (especially older parts of) Boost. It is sufficiently common that no future compiler could ever disable it or misoperate with it. I agree that could hinder significantly future C++ features, but that is not TypeIndex's problem because of so much preexisting usage. It's an established idiom, and that's that: in my opinion TypeIndex has the right to use established idioms if they are currently safe with all possible present compiler technologies as implied by the present C++ standard.
I don't agree that this is an idiom. I know that Boost.Move uses it, but I'm not aware of any other Boost library that does. Boost.Move is not nearly as problematic, because it only uses this in the fallback for C++03. It will eventually be phased out in C++11. In Christ, Steven Watanabe

On 15 Nov 2013 at 13:34, Steven Watanabe wrote:
problem because of so much preexisting usage. It's an established idiom, and that's that: in my opinion TypeIndex has the right to use established idioms if they are currently safe with all possible present compiler technologies as implied by the present C++ standard.
I don't agree that this is an idiom. I know that Boost.Move uses it, but I'm not aware of any other Boost library that does. Boost.Move is not nearly as problematic, because it only uses this in the fallback for C++03. It will eventually be phased out in C++11.
Let me clarify myself, as I've suddenly realised I was being unclear:
Let there be a DLL exporting function:
struct Foo { ... };
struct MoreFoo : Foo { ... };
MoreFoo &convert(Foo &in)
{
return static_cast

AMDG On 11/15/2013 01:58 PM, Niall Douglas wrote:
On 15 Nov 2013 at 13:34, Steven Watanabe wrote:
Let me clarify myself, as I've suddenly realised I was being unclear:
Let there be a DLL exporting function:
struct Foo { ... }; struct MoreFoo : Foo { ... };
MoreFoo &convert(Foo &in) { return static_cast
(in); // upcast to more derived type } Let there be another DLL in which we do:
MoreFoo a; auto b=convert(a); // legal Foo c; auto d=convert(c); // not legal
Where I was coming from was the case of the first DLL: there the compiler cannot know if the inbound Foo & originally came from a MoreFoo or not. It simply must proceed as if it did.
This doesn't prevent miscompiles when you do an illegal cast. The compiler doesn't have to prove that you're doing something illegal to miscompile your code. All it has to do is to say "This code is only legal if condition X holds, therefore I can assume that X is true and optimize accordingly."
That's what I meant by a very common idiom - we write code like the first DLL all the time where we cannot possibly know if we are doing undefined behaviour, because that's on the caller, not us. The shared library boundary makes avoiding this impossible.
Who is "we"? If you write a downcast like this, then the conditions that make it legal have to be considered a precondition of your function. This doesn't obviate the need for the types in the cast to be correct, it just changes who is responsible for it.
If we implement C++ Modules, then it all gets much more interesting, and that's what I was referring to about this idiom being a problem for future C++ features.
In Christ, Steven Watanabe

On Friday 15 November 2013 16:09:38 Niall Douglas wrote:
Here are my thoughts:
1. I would be happy with the static upcast if no virtual function table were in play because it's single inheritance, and static_cast provides enough safeguards (e.g. erroring if the type's inheritance tree is unknown at the point of static_cast use). It's a very common pattern in C++ code and is used throughout (especially older parts of) Boost. It is sufficiently common that no future compiler could ever disable it or misoperate with it. I agree that could hinder significantly future C++ features, but that is not TypeIndex's problem because of so much preexisting usage. It's an established idiom, and that's that: in my opinion TypeIndex has the right to use established idioms if they are currently safe with all possible present compiler technologies as implied by the present C++ standard.
I disagree. Virtual functions or type inheritance are not relevant. The standard is quite clear on this case (see 5.2.9/2), and compilers are allowed to mess up that code. The actually stored object is different from what the reference is being cast to. If a compiler, say, has to adjust the pointer as the part of static_cast, the resulting pointer would be invalid and any access to it would be another UB. I know you rely on the fact of single inheritance and assume that the pointer doesn't need any adjustment. But that is not guaranteed by the standard, and such language implementation would be valid. The preexisting practice is not an argument to me because that's not the kind of practice we'd like to preserve or advertise. That practice does cause a lot of headache from time to time. Gladly, such hacks are not that common nowdays.
2. Unfortunately, there IS a virtual function table, and therefore this line would fail:
dynamic_cast
(typeid(no_cvr_t)); where this line does not fail:
static_cast
(typeid(no_cvr_t)); That seems to me to be unacceptable. If a virtual function table is present, it MUST be correct with respect to the type the compiler is using it as.
So, Antony, if you can get the virtual function table to correctly say it's a boost::type_info and not a std::type_info, I'll recommend in my report this is fine. I don't mind a certain amount of evil :) to achieve that given it's such an isolated case which can be easily wrapped in a single location.
Ignoring the problem is not acceptable for a new library, IMO. The fact that some select compilers currently bear with such code doesn't mean they won't in the future, let alone there may be compilers that break it already. Putting that kind of jeopardy in the base of the library design is not a good solution by any measure. More so, when a cleaner solution is available.

On 16 Nov 2013 at 3:20, Andrey Semashev wrote:
Ignoring the problem is not acceptable for a new library, IMO. The fact that some select compilers currently bear with such code doesn't mean they won't in the future, let alone there may be compilers that break it already.
The point is moot as I have decided to recommend against this UB anyway. But unless my understanding of compiler technology is completely incorrect (and I am open to being corrected by a compiler vendor), I really don't think this particular UB if it were static only is a concern until a new C++ standard appears, and even then, a recompile would be needed to introduce breaking behaviour (at which point we can fix up the implementation for the new standard). This is my opinion of course, and if the review wizards disagree then I have no issue.
Putting that kind of jeopardy in the base of the library design is not a good solution by any measure. More so, when a cleaner solution is available.
The cleaner solution is not cost free - specifically, we now have to expend an extra eight (and probably sixteen) static bytes of additional binary size per type id i.e. code bloat. Personally, if it weren't for the virtual tables issue, I'd consider this particular UB worth saving that extra static memory consumption. It's not like this UB is hard to undo later if needs be. Given this extra bloat, we now have a new question: it is now worth making boost::type_info completely always std::type_info free i.e. it always uses the const char string from std::type_info::name() (or raw_name()) directly, and otherwise completely skips interacting with std::type_info at all? That ought to avoid having the linker emit a static std::type_info as it ought to spot it being unnecessary and elide it. That hopefully ought to substitute boost::type_info bloat for std::type_info bloat in a roughly balancing manner, so there is no net gain. Antony: you mentioned that your type_info needs to interop with std::type_info, and hence the need for convertibility? Can you explain that in more detail please? Can type_info be always set to template_info even with RTTI on, except that template_info will use std::type_info::name() instead of __PRETTY_FUNCTION__ when RTTI is on? Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On 15 Nov 2013 at 17:50, Antony Polukhin wrote:
I believe that this was a problem for Boost.Move with gcc, which does something similar. It's actually quite common for old C code that casts between different structs to fail with newer compilers. For instance, Python does not work without -fno-strict-aliasing.
Looks like I've got what are you talking about. It's an optimization in GCC, that assumes that if there is a reference to two different types and neither of those types is char, than those types are different in memory (are not aliases):
void foo(int64_t& v1, int32_t& v2) { /* GCC assumes that address of v1 is not a part of v2 adresses*/ v2 = 2; cout << v1; }
int64_t i64 = 1; foo(i64, reinterpret_cast
(i64)); // outputs 1 But this error appears only when we mutate data ( https://svn.boost.org/trac/boost/wiki/Guidelines/WarningsGuidelines search for "strict-aliasing rules")
This isn't really the same thing as Stephen mentioned. The above example is explicitly unrelated types i.e. a int64_t is not a int32_t, and the compiler is permitted to absolutely assume that to be true in the strongest possible way. The strict-aliasing problems in Python and the Linux kernel are due to them casting between unrelated structure types without the proper use of volatile qualification and/or going through void * or char * as the carrying opaque pointer type, such that the compiler's alias optimisation pass will assume that two unrelated type pointers will never refer to the same patch of memory which is permitted by the standard. Using volatile or void * or char * can inhibit that optimisation pass by disabling the ability to assume two pointers cannot refer to the same memory, and therefore inhibit unsafe code being generated. It is of course still undefined behaviour, but it's extremely common in C out of necessity. What TypeIndex does is much safer - it upcasts to a derived and therefore related type, and the compiler knows the types are related (or static_cast would fail). I cannot see how alias optimisation could ever therefore generate unsafe code in this case. Upcasting to a derived type is a very common - if often illegal - idiom in C++, but it is usually safe. It also saves programmers from writing a lot of extra boilerplate, hence its popularity. As I mentioned in the other post, for me it's the incorrectness of the virtual function table which kills this use of UB for me. Not the static upcast. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

AMDG On 11/15/2013 01:48 PM, Niall Douglas wrote:
As I mentioned in the other post, for me it's the incorrectness of the virtual function table which kills this use of UB for me. Not the static upcast.
You have the terminology backwards. Upcast mean derived to base. Downcast means base to derived. In Christ, Steven Watanabe

AMDG On 11/15/2013 01:48 PM, Niall Douglas wrote:
On 15 Nov 2013 at 17:50, Antony Polukhin wrote:
<snip> int64_t i64 = 1; foo(i64, reinterpret_cast
(i64)); // outputs 1 But this error appears only when we mutate data ( https://svn.boost.org/trac/boost/wiki/Guidelines/WarningsGuidelines search for "strict-aliasing rules")
This isn't really the same thing as Stephen mentioned.
In all essentials, it is the same. The precise rule that it violates is different, but it's still forbidden. "If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined" (C++11 9.3.1 [class.mfct.non-static]) In Christ, Steven Watanabe

On 15/11/2013 04:01, Quoth Steven Watanabe:
No, it is not harmless. You cannot safely assume that undefined behavior is ever harmless, just because you can't think of anything that can go wrong. In particular, the compiler is free to make assumptions that can cause your code to miscompile with optimizations on.
Another piece of undefined behaviour is with the RTTI information itself; if you tried to get the typeid/type_id of a type_info with RTTI enabled then you could get unexpected results. I don't know whether this would cause any issues in actual practice (since typeid(typeid(X)) is at least unusual, although not impossible especially once you get templates in the mix).

On 13/11/2013 08:34, Quoth Niall Douglas:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes: [...] 2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!)
There are several instances where code inside the boost namespace (and often within the class in question) refers to the same class with implicit namespace (eg. "type_info", eg. type_info.hpp:147), and elsewhere with explicit namespace (eg. "boost::type_info", eg. type_info.hpp:130). I don't know if there's an official policy on which of these two is preferred (though I think I've most commonly seen the namespace omitted), but it seems wrong to be inconsistent about it. Especially given that in type_info.hpp:73 there is, within namespace boost::detail, an implicit reference to *global* type_info. And of course boost::type_info itself potentially shadows global type_info and/or std::type_info, which may negatively impact code that does "using namespace boost". (Not that I think that should be encouraged, and this is not unique to this library now that eg. shared_ptr is in std with C++11.) I don't have a problem with this personally (and it fits the "drop in replacement" goal) but I'm not sure where Boost policies stand on this.

Hi, Quickly skimming the documentation and code I'm just wondering what exactly would be the problem if I were to do : template <class T> const type_info& my_type_id( const T& ) { return type_info::construct<T>(); } my_type_id( variable ) // instead of boost::type_id_rtti_only(variable) ? Thanks, MAT.

2013/11/15 Mathieu Champlon
Hi,
Quickly skimming the documentation and code I'm just wondering what exactly would be the problem if I were to do :
template <class T> const type_info& my_type_id( const T& ) { return type_info::construct<T>(); }
my_type_id( variable ) // instead of boost::type_id_rtti_only(variable)
?
type_info::construct<T>() works with the type T, while boost::type_id_rtti_only(variable) attempts to determinate the real type of variable. Here's an example: class Base { virtual *~*Base(){} }; class Derived: public Base {}; ... Derived d; Base& variable = d; my_type_id( variable ).name_demangled(); // returns `Base` boost::type_id_rtti_only(variable).name_demangled(); // returns `Derived ` -- Best regards, Antony Polukhin

On 15/11/2013 14:31, Antony Polukhin wrote:
type_info::construct<T>() works with the type T, while boost::type_id_rtti_only(variable) attempts to determinate the real type of variable.
OK, I see, thank you. Do you think getting the type info of the "current" type of a variable (as opposed to it's real type) could sometimes prove useful ? Could it be worth adding a function in TypeIndex ? Also using a local type as a template argument is illegal in C++03 (not in C++11 any more). For instance : void f() { struct s {}; boost::type_id< s >(); // illegal in C++03 typeid( s ); // legal } Maybe it should be stated in the documentation as this is an area where boost::type_id is not a drop-in replacement for typeid (in C++03) ? Cheers, MAT.

2013/11/16 Mathieu Champlon
Do you think getting the type info of the "current" type of a variable (as opposed to it's real type) could sometimes prove useful ? Could it be worth adding a function in TypeIndex ?
This is a very very common use case in Boost and widely used technique in libraries that use type erasure. Examples are Boost.Function, Boost.Any, Boost,Graph, Boost.Math and others... Such function is already in TypeIndex library, see boost::type_info<T>(). Also using a local type as a template argument is illegal in C++03 (not in
C++11 any more). For instance :
void f() { struct s {}; boost::type_id< s >(); // illegal in C++03 typeid( s ); // legal }
Maybe it should be stated in the documentation as this is an area where boost::type_id is not a drop-in replacement for typeid (in C++03) ?
Neat example, but I don't think that this must be mentioned in TypeIndex docs. This is a C++03 related restriction and a rare use case, so it will just complicate the docs. -- Best regards, Antony Polukhin

On 16/11/2013 16:58, Antony Polukhin wrote:
2013/11/16 Mathieu Champlon
<...> Do you think getting the type info of the "current" type of a variable (as opposed to it's real type) could sometimes prove useful ? Could it be worth adding a function in TypeIndex ?
This is a very very common use case in Boost and widely used technique in libraries that use type erasure. Examples are Boost.Function, Boost.Any, Boost,Graph, Boost.Math and others... Such function is already in TypeIndex library, see boost::type_info<T>().
Yes, but I meant given : #define SOME_MACRO_IN_MY_LIBRARY( variable ) do_something_complicated_requiring_type_info_of_type_of_variable I cannot use boost::type_info<T>() easily can I ? Granted I could do boost::type_info< BOOST_TYPEOF( variable ) >() but that's a bit cumbersome compared to for instance a simple boost::type_info( variable ). Thanks, MAT.

2013/11/16 Mathieu Champlon
On 16/11/2013 16:58, Antony Polukhin wrote:
2013/11/16 Mathieu Champlon
<...> (as opposed to it's real type) could sometimes prove useful ? Could it be worth adding a function in TypeIndex ?
This is a very very common use case in Boost and widely used technique in
Do you think getting the type info of the "current" type of a variable libraries that use type erasure. Examples are Boost.Function, Boost.Any, Boost,Graph, Boost.Math and others... Such function is already in TypeIndex library, see boost::type_info<T>().
Yes, but I meant given :
#define SOME_MACRO_IN_MY_LIBRARY( variable ) do_something_complicated_ requiring_type_info_of_type_of_variable
I cannot use boost::type_info<T>() easily can I ? Granted I could do boost::type_info< BOOST_TYPEOF( variable ) >() but that's a bit cumbersome compared to for instance a simple boost::type_info( variable ).
Sorry, I meant boost::type_id ( http://apolukhin.github.io/type_index/boost/type_id.html) Well, usually you have the type of the variable nearby, and can use it in type_id<T>: template <class T> void operator()(const T& var) { type_id<T>(); // no need in type_id(var); } ... int i; type_id<int>() // no need in type_id(i); Cases when it is hard to detect variable type are rare in Boost and I do not really wish to produce many trivial functions and make the library heavier. Anyway, user can always write such function in half a minute: tempalte <class T> inline const boost::type_info& my_type_id(const T&) { return boost::type_id<T>(); } -- Best regards, Antony Polukhin

On Tuesday 12 November 2013 14:34:27 Niall Douglas wrote:
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin.
First, let me thank Anthony for bringing this library to Boost. I think this is a long overdue addition, we've reinvented that wheel too many times already.
Feedback requested includes:
1. Should this library be accepted into Boost?
Yes, if the critical conditions below are met (otherwise no). After the required modifications to the library are made, another review is needed, maybe a fast track one.
2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!)
While reviewing the library I inspected the code and the documentation (mostly the Getting started and Examples sections). I did not compile the code or tests. There are a few critical issues that need to be resolved before the inclusion: * The undefined behavior of casting std::type_info const& to boost::type_info const& has to be removed. I described my preferred solution earlier in the discussion [1], but that particular solution is not a requirement. Anthony can of course choose another solution, as long as it solves the problem and does not undermine the library utility. * template_info construction involves unprotected function-local static variables and therefore is not thread-safe. The library should be thread-safe, even in C++03. * template_info::construct* functions should not be part of the class interface (or implementation). These functions should be an implementation detail of template_id() functions. The same is true for type_info::construct*, if type_info is preserved as a class after resolving the UB. In the end I'd like boost::type_info and boost::template_info interface and semantics to be as close to std::type_info as possible. * cvr_saver<> should be marked with BOOST_SYMBOL_VISIBLE. * The result of the discussion about name functions [2] should be taken into account, including if these functions turn out to be implemented in type_index. * BOOST_CLASSINFO_COMPARE_BY_NAMES macro should be named with the library name as its part (e.g. BOOST_TYPE_INDEX_COMPARE_BY_NAMES). It should probably be made user-definable, if this workaround is needed on some platform Boost doesn't cover. Also, I'm not sure it should be defined by default on gcc <4.5 and Intel on Linux. I'm pretty sure gcc on Linux worked fine since 4.1, if symbol visibility is set correctly (some later version of gcc added an attribute to simplify this) and it's hard to believe that no version of Intel works. Are these checks confirmed by tests? * Continuing the previous point, I can see that user_defined_namespace::user_defined class in libs/type_index/test/test_lib.cpp and testing_crossmodule.cpp are not marked with BOOST_SYMBOL_VISIBLE. This can make the cross-module test fail on a platform that actually supports cross-module RTTI comparison. The class should be marked visible for this test to work correctly. It may be worthwhile to move the class definition to test_lib.hpp to avoid duplication. * I'm not sure what is the purpose of the template_index typedef. It's not covered in the docs and it offers no advantage over type_index. I think, it is better to reduce responsibilities of the current template_info class so that it only mirrors std::type_info (i.e. it is nothing more than a low level type descriptor). Maybe even it should be only available as an implementation detail when RTTI is disabled. All the additional functionality, like ordering operators and name functions, are already provided by type_index, which should be used portably with and without RTTI enabled. In that case template_index is redundant and should be removed. * For the above point, tempate_info should not be copyable or assignable. It should not have stream operators as well. * I don't think that testing for macros like __FUNCSIG__ or __PRETTY_FUNCTION__ outside of a function body is correct. These are not the real macros, in the way they are only defined in a function body. There is also the standard __func__ macro that could be used by the library. I think that all the macro checks in template_info.hpp should be moved to the ctti<T>::n() function body. There is also no need for the lazy_function_signature_assert() function in that case (the assert can be embedded into n() directly). There are also some non-critical issues and wishes that I would like to be solved by the library. These points do not preclude the inclusion of the library and may be topics of discussion. * I'd like specialized functions template_id_with_cvr() and type_id_with_cvr() along with cvr_saver<> to be extracted to separate headers. The rationale for this is that this is an optional feature that is not always required. Separating it to dedicated headers can make the main headers more lightweight. * It might be a good idea to add template_info and type_info generator functions that do not preserve CVR qualification but still wrap the type with cvr_saver. The point of this is that cvr_saver would guarantee that the type is marked visible while the original type may not be. I'm using this trick in Boost.Log [3]. * I don't think type_id_rtti_only() is a good name. I'd suggest making these functions overloads of type_id() with no arguments and simply make them optional with #ifndef BOOST_NO_RTTI. I.e.: template< typename T > type_info const& type_id(); #ifndef BOOST_NO_RTTI template< typename T > type_info const& type_id(T*); template< typename T > type_info const& type_id(T&); #endif I think it is obvious enough that these functions obtain the dynamic type of the referred object and thus require native RTTI. * The support for std::hash can be added in a separate support header, that would be included by the user, if he wants to. By default, no other library headers would include this glue header, so there will be no compatibility issue if the particular standard library does not provide std::hash. The support for boost::hash (through the hash_value function) can be left as is. * In type_info::before() and hash_code() you unnecessarily call std::type_info::name() multiple times. This would likely be a library call. Please, avoid it, you can cache the name() result and use it multiple times. * The documentation could use a section explicitly describing the differences between the library behavior with and without native RTTI. Perhaps, a table comparing the two modes would be useful. * On platforms where we know we will be comparing type names when comparing std::type_infos (this includes Windows since MSVC does it internally, AFAIK) we could try first comparing the address of the type_infos, and only if it differs pass on to type_info::operator==. This may provide some speedup if the type_infos reside in a single module. * In template_info.hpp, please, don't include is_arithmetic.hpp, unless it's actually needed. * BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro could be made user-definable in case if there is some way to generate name strings not supported by Boost. * All configuration macros that affect the library (e.g. BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY, BOOST_TYPE_INDEX_COMPARE_BY_NAMES and BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) should be documented in a separate top-level section. BTW, may I suggest renaming BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY to just BOOST_TYPE_INDEX_FORCE_NO_RTTI. [1] http://article.gmane.org/gmane.comp.lib.boost.devel/246314 And the corrections in replies to that post. [2] http://article.gmane.org/gmane.comp.lib.boost.devel/246256 [3] http://svn.boost.org/svn/boost/trunk/boost/log/detail/visible_type.hpp PS: Wow, this turned out to be a much longer list than I anticipated. But let that not scare you, Anthony, overall the library is good and very useful, and I can't wait to see its inclusion.

2013/11/16 Andrey Semashev
2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!)
While reviewing the library I inspected the code and the documentation (mostly the Getting started and Examples sections). I did not compile the code or tests.
There are a few critical issues that need to be resolved before the inclusion:
* The undefined behavior of casting std::type_info const& to boost::type_info const& has to be removed. I described my preferred solution earlier in the discussion [1], but that particular solution is not a requirement. Anthony can of course choose another solution, as long as it solves the problem and does not undermine the library utility.
Question that disturbs me is, what type must be returned by the type_id<T>() method. Returning just a const std::type_info& seems almost useless, returning const boost::type_index& is not very portable/thread-safe because requires static const type_index variable construction. Must it return a type_index?
* BOOST_CLASSINFO_COMPARE_BY_NAMES macro should be named with the library name as its part (e.g. BOOST_TYPE_INDEX_COMPARE_BY_NAMES). It should probably be made user-definable, if this workaround is needed on some platform Boost doesn't cover. Also, I'm not sure it should be defined by default on gcc <4.5 and Intel on Linux. I'm pretty sure gcc on Linux worked fine since 4.1, if symbol visibility is set correctly (some later version of gcc added an attribute to simplify this) and it's hard to believe that no version of Intel works. Are these checks confirmed by tests?
It is a known bug with GCC on ARM architecture. Additional testing required to check, is it safe to use GCC's comparisons on x86. This can be done later, not during the library review.
* I don't think type_id_rtti_only() is a good name. I'd suggest making these functions overloads of type_id() with no arguments and simply make them optional with #ifndef BOOST_NO_RTTI. I.e.:
template< typename T > type_info const& type_id();
#ifndef BOOST_NO_RTTI template< typename T > type_info const& type_id(T*); template< typename T > type_info const& type_id(T&); #endif
Returning just a std::type_info will require additional care from the user to compare type_infos correctly. Returning a type_index will solve that problem. How about just having a copyable, hashable boost::type_index class that is comparable with std::type_info (something close to v1.0 of TypeIndex)? In that case the library will have anly a boost::type_info typedef, boost::type_index class for RTTI and boost::template_index for situation when RTTI is off. -- Best regards, Antony Polukhin

On Saturday 16 November 2013 19:46:25 Antony Polukhin wrote:
2013/11/16 Andrey Semashev
<...> 2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!)
While reviewing the library I inspected the code and the documentation (mostly the Getting started and Examples sections). I did not compile the code or tests.
There are a few critical issues that need to be resolved before the inclusion:
* The undefined behavior of casting std::type_info const& to boost::type_info const& has to be removed. I described my preferred solution earlier in the discussion [1], but that particular solution is not a requirement. Anthony can of course choose another solution, as long as it solves the problem and does not undermine the library utility.
Question that disturbs me is, what type must be returned by the type_id<T>() method. Returning just a const std::type_info& seems almost useless, returning const boost::type_index& is not very portable/thread-safe because requires static const type_index variable construction. Must it return a type_index?
My understanding was that type_id() is intended to be the portable alternative for operator typeid(). If that's the case it should return boost::type_info const&. However, I can see the convenience of returning type_index right away. This will encourage the use of type_index instead of type_info and maybe that's the right thing to do.
* BOOST_CLASSINFO_COMPARE_BY_NAMES macro should be named with the library name as its part (e.g. BOOST_TYPE_INDEX_COMPARE_BY_NAMES). It should probably be made user-definable, if this workaround is needed on some platform Boost doesn't cover. Also, I'm not sure it should be defined by default on gcc <4.5 and Intel on Linux. I'm pretty sure gcc on Linux worked fine since 4.1, if symbol visibility is set correctly (some later version of gcc added an attribute to simplify this) and it's hard to believe that no version of Intel works. Are these checks confirmed by tests?
It is a known bug with GCC on ARM architecture. Additional testing required to check, is it safe to use GCC's comparisons on x86. This can be done later, not during the library review.
Then the condition should also include checks for the ARM target (see boost/atomic/detail/platform.hpp for example).
* I don't think type_id_rtti_only() is a good name. I'd suggest making these functions overloads of type_id() with no arguments and simply make them optional with #ifndef BOOST_NO_RTTI. I.e.:
template< typename T > type_info const& type_id();
#ifndef BOOST_NO_RTTI template< typename T > type_info const& type_id(T*); template< typename T > type_info const& type_id(T&); #endif
Returning just a std::type_info will require additional care from the user to compare type_infos correctly. Returning a type_index will solve that problem.
Yes. Ok, let it return type_index then.
How about just having a copyable, hashable boost::type_index class that is comparable with std::type_info (something close to v1.0 of TypeIndex)? In that case the library will have anly a boost::type_info typedef, boost::type_index class for RTTI and boost::template_index for situation when RTTI is off.
I don't think there's any use for template_index, as I outlined in my review. type_index already has all the functionality and should work whether or not RTTI is enabled. type_index need not be directly comparable with std::type_info because it is implicitly convertible from it. The comparison operators between just type_indexes will work. Other than that such design looks good to me.

2013/11/16 Andrey Semashev
On Saturday 16 November 2013 19:46:25 Antony Polukhin wrote:
2013/11/16 Andrey Semashev
<...> I don't think there's any use for template_index, as I outlined in my
review. type_index already has all the functionality and should work whether or not RTTI is enabled.
template_index and type_index are two different types intentionally. It's the last attempt to notify user that he has done something wrong: // This is an interface of some library. Library is compiled without RTTI, // user uses this header with RTTI on. void some_function(boost::type_index& ti); If template_index and type_index are two different types and BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY is not defined, then user will get a linker error on GCC. If those two classes were exactly the same type, there'll be no link error. But user will get undefined behavior with hard detectable errors. Thanks for very good advices and a big review! -- Best regards, Antony Polukhin

On Saturday 16 November 2013 22:15:18 Antony Polukhin wrote:
2013/11/16 Andrey Semashev
On Saturday 16 November 2013 19:46:25 Antony Polukhin wrote:
2013/11/16 Andrey Semashev
<...>
I don't think there's any use for template_index, as I outlined in my
review. type_index already has all the functionality and should work whether or not RTTI is enabled.
template_index and type_index are two different types intentionally. It's the last attempt to notify user that he has done something wrong:
// This is an interface of some library. Library is compiled without RTTI, // user uses this header with RTTI on. void some_function(boost::type_index& ti);
If template_index and type_index are two different types and BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY is not defined, then user will get a linker error on GCC. If those two classes were exactly the same type, there'll be no link error. But user will get undefined behavior with hard detectable errors.
That does not require two different types, such as template_index and type_index. You can define a single type_index in an inline namespace, which name depends on the use of native RTTI. For C++03, a regular namespace and a using declaration would suffice. That way all user's code will just always use type_index, and there will be linking errors in case of configuration inconsistencies. Having two different interface classes instead divides the world in two parts and creates integration problems for users. Imagine library A uses template_index and library B uses type_index. How would these libraries coexist in a user's application, which is happy to use native RTTI? And what are the guidelines for library writers on choosing between these two types? IMO, there should be a single type_index class, which should work in both modes.

On 16 Nov 2013 at 16:53, Andrey Semashev wrote:
Feedback requested includes:
1. Should this library be accepted into Boost?
Yes, if the critical conditions below are met (otherwise no). After the required modifications to the library are made, another review is needed, maybe a fast track one.
A very comprehensive feedback, and very useful for my report. Thank you Andrey! Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On Tue, Nov 12, 2013 at 8:34 PM, Niall Douglas
Boost community feedback is requested for the formal peer review of the TypeIndex library by Antony Polukhin. Feedback requested includes:
1. Should this library be accepted into Boost?
YES. First, because the documentation clarified issues I do have but didn't realized I have yet (I guess I would have found out once I start porting my project to another compiler). I do use a lot of type_index as keys in different containers (including tbb concurrent associative containers) and a lot of the ids will come from runtime shared libraries loaded and unloaded when needed. (mostly I use them in different type-based message dispatching systems) So the documentation was a surprise and I'm happy to see that there are potential solutions. Second: I'm ok with either way of doing, to make boost::type_id and boost::type_index similar to std:: ones or to have a more consistent behaviour across platforms for boost ones. I'm not sure which one is preferable, but I would make sure to use in my own code the way that would allow me to have the exact (or almost exact) same behaviour whatever the platform (if possible). Whatever the way this library ends, I think I should used it as, as I was saying, I'm using a lot type index. One question though, I'm not totally clear if there is a remarkable difference in performance and binary size between with RTTI using std and without RTTI using this library. I understand that performance wasn't the concern but I might have missed useful indication on potential consequences of using this library. I read most of the documentation though I think I should re-read some parts as I was interrupted frequently through my reading.
2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!)
I don't have a particular condition, I'm not knowledgeable enough in the details of the library to even participate to the discussion.

On 17 Nov 2013 at 0:41, Klaim - Joël Lamotte wrote:
1. Should this library be accepted into Boost?
YES.
Thanks for the feedback. Very useful for my report.
One question though, I'm not totally clear if there is a remarkable difference in performance and binary size between with RTTI using std and without RTTI using this library.
You make a valid point. It's been many years since I last wrote code capable of working with RTTI off, and therefore my knowledge of how well modern compilers generate RTTI is seriously out of date. I have probably been overly conservative as a result by working with a decade old mental model. Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On Nov 12, 2013, at 2:34 PM, "Niall Douglas"
1. Should this library be accepted into Boost?
No, not in its present state.
2. Any conditions which should be attached to acceptance into Boost e.g. fixes, additional testing, changes to documentation. Please be as specific as possible here (bullet points are good!)
I'm totally confused as to what library would be added to Boost, if it were even conditionally accepted. There have been myriad suggestions and ideas for altering the submitted library, it isn't worth my time to study the submission now. Names will change. Return types will change. Derivations will change. Performance characteristics will change. I would prefer that the library be updated, to address the issues raised, and then be submitted for another formal review.
What is Boost.TypeIndex?
TypeIndex performs three main functions:
1. It provides a consistent, well defined, portable boost::typeid() implementation with a consistent, well defined, portable boost::type_info class implementation which mirrors std::type_info.
That's a worthwhile purpose.
Implementation-specific weirdnesses (e.g. std::type_info::raw_name(), the fact the hash_code is often terrible and collides frequently) are abstracted out into a single, portable API.
2. It provides the ability to convert a type into a uniquely identifiable, container indexable, boost::type_info instance (e.g. &typeid(T) or C++11 class std::type_index) with RTTI disabled, thereby removing the need for requiring RTTI enabled for many type_info use cases.
Those are useful capabilities. ___ Rob (Sent from my portable computation engine)

On 18 Nov 2013 at 7:16, Rob Stewart wrote:
1. Should this library be accepted into Boost?
No, not in its present state.
Firstly, thank you for the feedback. Very useful for my report. A reminder to the list: peer review period ends tomorrow Thurs 21st Nov. I will write up a report on all the feedback sometime this weekend (I have a complex systems conference at UW all day Thurs and Fri, indeed I'm convening one of the sessions), and I would assume the peer review wizards will probably want another round of peer review, hopefully this time a short (five day) round. My thanks to everyone who has contributed so far. Your peer review is what makes Boost what it is! Niall -- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/

On Wednesday 20 November 2013 11:09:20 Niall Douglas wrote:
On 18 Nov 2013 at 7:16, Rob Stewart wrote:
1. Should this library be accepted into Boost?
No, not in its present state.
Firstly, thank you for the feedback. Very useful for my report.
A reminder to the list: peer review period ends tomorrow Thurs 21st Nov. I will write up a report on all the feedback sometime this weekend (I have a complex systems conference at UW all day Thurs and Fri, indeed I'm convening one of the sessions), and I would assume the peer review wizards will probably want another round of peer review, hopefully this time a short (five day) round.
May I ask that a weekend is within the new review time frame? Some people don't have much free time on workdays.

Only from reading documentation I have a few questions: 1. In http://apolukhin.github.io/type_index/boost_typeindex/examples.html#boost_ty... is written that polymorphic types can't be identified without RTTI. It should be possible for a library user to make his types compatible with Boost.TypeIndex to identify them. For example he can return boost::type_info from a virtual function inside each class: struct A { virtual ~A(){} virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<A>()); } }; struct B: public A { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<B>()); } }; struct C: public B { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<C>()); } }; Boost.TypeIndex should provide a way to use such methods inside boost::type_id_rtti_only. Is something like this planned? 2. As far as I understand almost everything inside the library is build on top of string comparison. All these strings are available at compile time. Are there plans to make boost::template_info a literal type? It would help with metaprogramming to have a system representing types with the same set of operations and behavior at compile time and run time (I think of sorting classes at compile time, store boost::template_info of them in an array and use some binary search at run time). 3. What are he exact reasons for storing types with const, volatile and reference in boost::type_id_with_cvr? As long as there is no way to query this information and remove it at run time I think it would better users store them together with type_index if the need this feature. It could result in hard to find errors when users use type_if_with_cvr in one module and not expecting them in another. Jan Herrmann

2013/11/21 Jan Herrmann
Only from reading documentation I have a few questions:
1. In http://apolukhin.github.io/type_index/boost_typeindex/ examples.html#boost_typeindex.examples.getting_through_the_inheritance_is written that polymorphic types can't be identified without RTTI. It should be possible for a library user to make his types compatible with Boost.TypeIndex to identify them. For example he can return boost::type_info from a virtual function inside each class:
struct A { virtual ~A(){} virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<A>()); } }; struct B: public A { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<B>()); } }; struct C: public B { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<C>()); } };
Boost.TypeIndex should provide a way to use such methods inside boost::type_id_rtti_only. Is something like this planned?
This looks like a *very* good addition, thanks for the idea! This will be implemented as soon as possible (before the next review).
2. As far as I understand almost everything inside the library is build on top of string comparison. All these strings are available at compile time. Are there plans to make boost::template_info a literal type? It would help with metaprogramming to have a system representing types with the same set of operations and behavior at compile time and run time (I think of sorting classes at compile time, store boost::template_info of them in an array and use some binary search at run time).
This can be interesting. That feature will be implemented, however I do not see how this could be possible to do in C++03/C++98.
3. What are he exact reasons for storing types with const, volatile and reference in boost::type_id_with_cvr? As long as there is no way to query this information and remove it at run time I think it would better users store them together with type_index if the need this feature. It could result in hard to find errors when users use type_if_with_cvr in one module and not expecting them in another.
This is done for libraries that use type erasure technique a lot. Sometimes
there may be a need to store those modifiers (there was an example in
examples section for that case:
http://apolukhin.github.io/type_index/boost_typeindex/examples.html#boost_ty...)
There must be no problems with mixing boost::type_id_with_cvr and
boost::type_id. If there are no modifiers, result will be the same:
boost::type_id_with_cvr<int>() == boost::type_id<int>()
boost::type_id_with_cvr

On 21.11.2013 16:57, Antony Polukhin wrote:
2013/11/21 Jan Herrmann
Only from reading documentation I have a few questions:
1. In http://apolukhin.github.io/type_index/boost_typeindex/ examples.html#boost_typeindex.examples.getting_through_the_inheritance_is written that polymorphic types can't be identified without RTTI. It should be possible for a library user to make his types compatible with Boost.TypeIndex to identify them. For example he can return boost::type_info from a virtual function inside each class:
struct A { virtual ~A(){} virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<A>()); } }; struct B: public A { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<B>()); } }; struct C: public B { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<C>()); } };
Boost.TypeIndex should provide a way to use such methods inside boost::type_id_rtti_only. Is something like this planned?
This looks like a *very* good addition, thanks for the idea! This will be implemented as soon as possible (before the next review).
I think some macros can make it very easy to implement this for clients.
2. As far as I understand almost everything inside the library is build on top of string comparison. All these strings are available at compile time. Are there plans to make boost::template_info a literal type? It would help with metaprogramming to have a system representing types with the same set of operations and behavior at compile time and run time (I think of sorting classes at compile time, store boost::template_info of them in an array and use some binary search at run time).
This can be interesting. That feature will be implemented, however I do not see how this could be possible to do in C++03/C++98.
Yes it's only possible with constexpr, but I see your work as a part for building better TypeIndex like systems. Users should be able to build their own RTTI system with information about types they need. For example a RTTI system could provide information about size and alignment or provide a type erased clone implementation (from a void* to void* with same type).
3. What are he exact reasons for storing types with const, volatile and reference in boost::type_id_with_cvr? As long as there is no way to query this information and remove it at run time I think it would better users store them together with type_index if the need this feature. It could result in hard to find errors when users use type_if_with_cvr in one module and not expecting them in another.
This is done for libraries that use type erasure technique a lot. Sometimes there may be a need to store those modifiers (there was an example in examples section for that case: http://apolukhin.github.io/type_index/boost_typeindex/examples.html#boost_ty...)
There must be no problems with mixing boost::type_id_with_cvr and boost::type_id. If there are no modifiers, result will be the same:
boost::type_id_with_cvr<int>() == boost::type_id<int>() boost::type_id_with_cvr
() == boost::type_id () Or am I missing some use case?
I see type erasure in conjunction with type recovery. And I think these bits of information are not worth. If it is possible that somebody calls boost::type_id_with_cvr in one module other modules which needs to probe for types have to check every type 12 times (2 (const) x 2 (volatile) x 3(no ref, ref, rvalue rev). Think of implementing a ad-hoc visitor (http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813) with TypeIndex and void*. When implementing a function which only needs a const value client has to probe for const and non-const types only to get a const value out of it. I'm not sure whether volatile should be considered. For example no container in std has overloads for volatile access to elements, but they are all const correct. References are another problem. In case of type erased storage they are very distinct form values but sometimes they should be used like values. If I remember correctly there where long debates about std::optional and references in isocpp.proposals or general this year. Arguments could be same here. I wouldn't feel comfortable to work with type properties without being able to query them. Type recovery is hard enough. But if somebody needs these information there are a few ways. One would be to align type_index at a 8 Byte boundary so users could store pointers and would have 4 bits. The other option is to let users build their own facilities via composition of some state variable and type_index. Jan Herrmann

2013/11/21 Jan Herrmann
On 21.11.2013 16:57, Antony Polukhin wrote:
2013/11/21 Jan Herrmann
Only from reading documentation I have a few questions:
1. In http://apolukhin.github.io/type_index/boost_typeindex/ examples.html#boost_typeindex.examples.getting_through_the_inheritance_is written that polymorphic types can't be identified without RTTI. It
should be possible for a library user to make his types compatible with Boost.TypeIndex to identify them. For example he can return boost::type_info from a virtual function inside each class:
struct A { virtual ~A(){} virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<A>()); } }; struct B: public A { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<B>()); } }; struct C: public B { virtual boost::type_info const& get_boost_type_info() const { return boost::type_id<C>()); } };
Boost.TypeIndex should provide a way to use such methods inside boost::type_id_rtti_only. Is something like this planned?
This looks like a *very* good addition, thanks for the idea! This will be implemented as soon as possible (before the next review).
I think some macros can make it very easy to implement this for clients.
Yes.
I'm also thinking of an ability for client to provide it's own names for a
type. For example
boost::variant
2. As far as I understand almost everything inside the library is build on
top of string comparison. All these strings are available at compile time. Are there plans to make boost::template_info a literal type? It would help with metaprogramming to have a system representing types with the same set of operations and behavior at compile time and run time (I think of sorting classes at compile time, store boost::template_info of them in an array and use some binary search at run time).
This can be interesting. That feature will be implemented, however I do not see how this could be possible to do in C++03/C++98.
Yes it's only possible with constexpr, but I see your work as a part for
building better TypeIndex like systems. Users should be able to build their own RTTI system with information about types they need. For example a RTTI system could provide information about size and alignment or provide a type erased clone implementation (from a void* to void* with same type).
This is a very big goal and TypeIndex was not initially intended to solve such problems. This can be added some time later (after additional mini review), not in the initial version.
3. What are he exact reasons for storing types with const, volatile and
reference in boost::type_id_with_cvr? As long as there is no way to query this information and remove it at run time I think it would better users store them together with type_index if the need this feature. It could result in hard to find errors when users use type_if_with_cvr in one module and not expecting them in another.
This is done for libraries that use type erasure technique a lot. Sometimes there may be a need to store those modifiers (there was an example in examples section for that case:
http://apolukhin.github.io/type_index/boost_typeindex/examples.html#boost_ty... )
There must be no problems with mixing boost::type_id_with_cvr and boost::type_id. If there are no modifiers, result will be the same:
boost::type_id_with_cvr<int>() == boost::type_id<int>() boost::type_id_with_cvr
() == boost::type_id () Or am I missing some use case?
I see type erasure in conjunction with type recovery. And I think these
bits of information are not worth. If it is possible that somebody calls boost::type_id_with_cvr in one module other modules which needs to probe for types have to check every type 12 times (2 (const) x 2 (volatile) x 3(no ref, ref, rvalue rev). Think of implementing a ad-hoc visitor ( http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813) with TypeIndex and void*. When implementing a function which only needs a const value client has to probe for const and non-const types only to get a const value out of it. I'm not sure whether volatile should be considered. For example no container in std has overloads for volatile access to elements, but they are all const correct. References are another problem. In case of type erased storage they are very distinct form values but sometimes they should be used like values. If I remember correctly there where long debates about std::optional and references in isocpp.proposals or general this year. Arguments could be same here.
I wouldn't feel comfortable to work with type properties without being able to query them. Type recovery is hard enough.
But if somebody needs these information there are a few ways. One would be to align type_index at a 8 Byte boundary so users could store pointers and would have 4 bits. The other option is to let users build their own facilities via composition of some state variable and type_index.
Think of it in another way: its a way to preserve old functionality.
boost::type_id<T>() will remove all the cvr modifiers, but there might be
some users that rely on a behavior of their current compiler and still wish
to save those modifiers. So if we provide a function that removes cvr,
there must be an ability so save cvr.
What modifiers really matter to user - is up to user. If user needs only
references, it is possible for him to save only them:
#include
Jan Herrmann
Thanks for the good ideas! -- Best regards, Antony Polukhin
participants (12)
-
Andrey Semashev
-
Antony Polukhin
-
Gavin Lambert
-
Gottlob Frege
-
Jan Herrmann
-
Klaim - Joël Lamotte
-
Mathieu Champlon
-
Niall Douglas
-
pfultz2
-
Rob Stewart
-
Steven Watanabe
-
Vicente J. Botet Escriba