[type_traits] is_base_of<B, D> should work when B is incomplete
Hi, I have filed the following ticket: https://svn.boost.org/trac/boost/ticket/12027 The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted? Regards, &rzej
On 03.03.2016, at 22:57, Andrzej Krzemienski
wrote: The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted?
That would probably be possible for all modern compilers that have a proper std::is_base_of because it requires a compiler intrinsic (unless you can implement it without such an intrinsic and in C++98). Boost.TypeTraits have quite a history and by lifting the restriction, you would drop support for old compilers (think pre-C++11). And if you really need this feature, why not use std::is_base_of directly? Either your compiler has it or it can’t be implemented AFAICT.
On Thu, Mar 3, 2016 at 5:18 PM, Daniel Frey
On 03.03.2016, at 22:57, Andrzej Krzemienski
wrote: The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted?
That would probably be possible for all modern compilers that have a proper std::is_base_of because it requires a compiler intrinsic (unless you can implement it without such an intrinsic and in C++98). Boost.TypeTraits have quite a history and by lifting the restriction, you would drop support for old compilers (think pre-C++11).
Excluding C++98 support, why do you need a compiler intrinsic for this change? If the reason is the incompleteness check, I've implemented completeness checking metafunctions before and it's fully possible without intrinsics in C++11. I described a completeness metafunction that works in practice a few years ago in a discussion on the mailing list here: https://groups.google.com/forum/#!topic/boost-developers-archive/zp7u3XHv6zc which links to an implementation here: http://codepaste.net/xfgcu8 (there are subtleties to usage, of course). The code that is linked is old and not fully correct, although in the time since that thread, I have produced what I believe to be a fully correct and well tested implementation. -- -Matt Calabrese
On Thu, Mar 3, 2016 at 5:33 PM, Matt Calabrese
The code that is linked is old and not fully correct, although in the time since that thread, I have produced what I believe to be a fully correct and well tested implementation.
Also, to clarify, the reason why that code isn't fully correct is that it doesn't work for certain kinds of types, such as reference types. There were likely other changes, though I don't have the fully correct implementation in front of me. It was not very complicated, though. -- -Matt Calabrese
On 03.03.2016, at 23:33, Matt Calabrese
wrote: Excluding C++98 support, why do you need a compiler intrinsic for this change? If the reason is the incompleteness check, I've implemented completeness checking metafunctions before and it's fully possible without intrinsics in C++11. I described a completeness metafunction that works in practice a few years ago in a discussion on the mailing list here: https://groups.google.com/forum/#!topic/boost-developers-archive/zp7u3XHv6zc which links to an implementation here: http://codepaste.net/xfgcu8 (there are subtleties to usage, of course). The code that is linked is old and not fully correct, although in the time since that thread, I have produced what I believe to be a fully correct and well tested implementation.
That is a very interesting technique, I didn’t knew about it. But if std::is_base_of is available, boost::is_base_of should surely just forward to it, so only those compilers that don’t have it (aka mostly pre-C++11 compilers) are of interest here. Maybe lifting the restriction (and using an alternative implementation) should be conditional, only to be guaranteed by boost::is_base_of when compiling with C++11 or newer?
On 4/03/2016 12:24, Daniel Frey wrote:
But if std::is_base_of is available, boost::is_base_of should surely just forward to it, so only those compilers that don’t have it (aka mostly pre-C++11 compilers) are of interest here. Maybe lifting the restriction (and using an alternative implementation) should be conditional, only to be guaranteed by boost::is_base_of when compiling with C++11 or newer?
I think the operative question is, why would you use it? If you know you have C++11 compilers always, then use std::is_base_of and your code can use complete or incomplete types as you wish. If you don't know you have C++11 compilers always, then use boost::is_base_of and restrict yourself to complete types. If you're using the Boost version to broaden compiler support, then your code would not compile (or would produce different results) depending which environment you compiled it in. So you could end up with code that works in development but fails in production.
On 3/3/16 15:24, Daniel Frey wrote:
On 03.03.2016, at 23:33, Matt Calabrese
wrote: <snip> That is a very interesting technique, I didn’t knew about it. But if std::is_base_of is available, boost::is_base_of should surely just forward to it, so only those compilers that don’t have it (aka mostly pre-C++11 compilers) are of interest here. Maybe lifting the restriction (and using an alternative implementation) should be conditional, only to be guaranteed by boost::is_base_of when compiling with C++11 or newer?
I am really *not* a fan of this. It breaks things that shouldn't be broken by changing the implementation based on the compiler. This sometimes results in different and surprising behaviour. If I'm asking for the Boost version, I actually want the Boost version and not the compiler's std library version. michael
On 04.03.2016, at 05:22, Michael Caisse
wrote: On 3/3/16 15:24, Daniel Frey wrote:
On 03.03.2016, at 23:33, Matt Calabrese
wrote: <snip> That is a very interesting technique, I didn’t knew about it. But if std::is_base_of is available, boost::is_base_of should surely just forward to it, so only those compilers that don’t have it (aka mostly pre-C++11 compilers) are of interest here. Maybe lifting the restriction (and using an alternative implementation) should be conditional, only to be guaranteed by boost::is_base_of when compiling with C++11 or newer?
I am really *not* a fan of this. It breaks things that shouldn't be broken by changing the implementation based on the compiler. This sometimes results in different and surprising behaviour. If I'm asking for the Boost version, I actually want the Boost version and not the compiler's std library version.
I’m also not a fan of changing it. Use std::is_base_of if possible and boost::is_base_of when not. Regardless, my suggestion would not break anything. It will only provide an additional feature starting with a compiler that implements (and is configured to use) C++11 (or newer). And the old version would result in a compile-time error when using this feature, so it won’t silently change the behavior of existing code. But again, I don’t really see a need for the change either. Daniel
2016-03-03 23:33 GMT+01:00 Matt Calabrese
On Thu, Mar 3, 2016 at 5:18 PM, Daniel Frey
wrote: On 03.03.2016, at 22:57, Andrzej Krzemienski
wrote: The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted?
That would probably be possible for all modern compilers that have a proper std::is_base_of because it requires a compiler intrinsic (unless you can implement it without such an intrinsic and in C++98). Boost.TypeTraits have quite a history and by lifting the restriction, you would drop support for old compilers (think pre-C++11).
Excluding C++98 support, why do you need a compiler intrinsic for this change? If the reason is the incompleteness check, I've implemented completeness checking metafunctions before and it's fully possible without intrinsics in C++11. I described a completeness metafunction that works in practice a few years ago in a discussion on the mailing list here:
https://groups.google.com/forum/#!topic/boost-developers-archive/zp7u3XHv6zc which links to an implementation here: http://codepaste.net/xfgcu8 (there are subtleties to usage, of course). The code that is linked is old and not fully correct, although in the time since that thread, I have produced what I believe to be a fully correct and well tested implementation.
This is quite interesting. However, for my particular purpose, I may not need to employ a C++11 solution. I have an incomplete type boost::in_place_factory. I want to check if a given type T is either derived from boost::in_place_factory. It doesn't have to be very strict: it can get false negative on multiple inheritance; it can give a false positive when T is implicitly convertible to boost::in_place_factory by other means, or simply return false_type when boost::in_place_factory is incomplete. Perhaps there is a C++03-compatible solution to this particular problem? Regards, &rzej
2016-03-04 9:24 GMT+01:00 Andrzej Krzemienski
2016-03-03 23:33 GMT+01:00 Matt Calabrese
: On Thu, Mar 3, 2016 at 5:18 PM, Daniel Frey
wrote: On 03.03.2016, at 22:57, Andrzej Krzemienski
wrote: The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted?
That would probably be possible for all modern compilers that have a proper std::is_base_of because it requires a compiler intrinsic (unless you can implement it without such an intrinsic and in C++98). Boost.TypeTraits have quite a history and by lifting the restriction, you would drop support for old compilers (think pre-C++11).
Excluding C++98 support, why do you need a compiler intrinsic for this change? If the reason is the incompleteness check, I've implemented completeness checking metafunctions before and it's fully possible without intrinsics in C++11. I described a completeness metafunction that works in practice a few years ago in a discussion on the mailing list here:
https://groups.google.com/forum/#!topic/boost-developers-archive/zp7u3XHv6zc which links to an implementation here: http://codepaste.net/xfgcu8 (there are subtleties to usage, of course). The code that is linked is old and not fully correct, although in the time since that thread, I have produced what I believe to be a fully correct and well tested implementation.
This is quite interesting. However, for my particular purpose, I may not need to employ a C++11 solution.
I have an incomplete type boost::in_place_factory. I want to check if a given type T is either derived from boost::in_place_factory. It doesn't have to be very strict: it can get false negative on multiple inheritance; it can give a false positive when T is implicitly convertible to boost::in_place_factory by other means, or simply return false_type when boost::in_place_factory is incomplete.
Perhaps there is a C++03-compatible solution to this particular problem?
Actually, I do not even need a true-false answer; I just need to disable an overload (in SFINAE sense) if boost::in_place_factory is either incomplete or not a base class of T.
I have an incomplete type boost::in_place_factory. I want to check if a given type T is either derived from boost::in_place_factory. It doesn't have to be very strict: it can get false negative on multiple inheritance; it can give a false positive when T is implicitly convertible to boost::in_place_factory by other means, or simply return false_type when boost::in_place_factory is incomplete.
Perhaps there is a C++03-compatible solution to this particular problem?
Actually, I do not even need a true-false answer; I just need to disable an overload (in SFINAE sense) if boost::in_place_factory is either incomplete or not a base class of T.
This may be fixable (or alternatively the fix may just break a ton of things.... we'll see), but I'm curious why in_place_factory needs to be incomplete - surely if you handle that base class a special case then you need it's definition anyway? In any case why not just include the header and be done with? Thanks, John.
2016-03-04 10:24 GMT+01:00 John Maddock
I have an incomplete type boost::in_place_factory. I want to check if a
given type T is either derived from boost::in_place_factory. It doesn't have to be very strict: it can get false negative on multiple inheritance; it can give a false positive when T is implicitly convertible to boost::in_place_factory by other means, or simply return false_type when boost::in_place_factory is incomplete.
Perhaps there is a C++03-compatible solution to this particular problem?
Actually, I do not even need a true-false answer; I just need to disable an overload (in SFINAE sense) if boost::in_place_factory is either incomplete or not a base class of T.
This may be fixable (or alternatively the fix may just break a ton of things.... we'll see), but I'm curious why in_place_factory needs to be incomplete - surely if you handle that base class a special case then you need it's definition anyway? In any case why not just include the header and be done with?
Thanks, John.
This used to be an option, until we introduced the concept of Boost library dependencies. If I include a header with an empty definition of boost::in_place_factory_base, I introduce a dependency between Boost.Optional and Boost.Utility. And hardly anyone will need it, as the functionality offered by in-place factories is obsolete in C++11. boost::in_place_factory_base is meant only to be a "tag": if you derive from it we trigger a special path for your type. It is interesting that my problem only occurs on these experimental oracle-sparc-S2-12.5-cpp11 http://www.boost.org/development/tests/develop/oracle-sparc-S2-12-5-cpp11.ht... It implements rvalue references, decltype, variadic templates, but no type_traits. Regards, &rzej
Andrzej Krzemienski wrote:
This used to be an option, until we introduced the concept of Boost library dependencies.
If I include a header with an empty definition of boost::in_place_factory_base, I introduce a dependency between Boost.Optional and Boost.Utility.
This is not a problem at the moment because Optional already requires
Utility:
C:\Projects\boost-git\boost>dist\bin\boostdep optional
Primary dependencies for optional:
[...]
utility:
On 2016-03-04 11:36, Andrzej Krzemienski wrote:
2016-03-04 9:24 GMT+01:00 Andrzej Krzemienski
: 2016-03-03 23:33 GMT+01:00 Matt Calabrese
: On Thu, Mar 3, 2016 at 5:18 PM, Daniel Frey
wrote: On 03.03.2016, at 22:57, Andrzej Krzemienski
wrote: The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted?
That would probably be possible for all modern compilers that have a proper std::is_base_of because it requires a compiler intrinsic (unless you can implement it without such an intrinsic and in C++98). Boost.TypeTraits have quite a history and by lifting the restriction, you would drop support for old compilers (think pre-C++11).
Excluding C++98 support, why do you need a compiler intrinsic for this change? If the reason is the incompleteness check, I've implemented completeness checking metafunctions before and it's fully possible without intrinsics in C++11. I described a completeness metafunction that works in practice a few years ago in a discussion on the mailing list here:
https://groups.google.com/forum/#!topic/boost-developers-archive/zp7u3XHv6zc which links to an implementation here: http://codepaste.net/xfgcu8 (there are subtleties to usage, of course). The code that is linked is old and not fully correct, although in the time since that thread, I have produced what I believe to be a fully correct and well tested implementation.
This is quite interesting. However, for my particular purpose, I may not need to employ a C++11 solution.
I have an incomplete type boost::in_place_factory. I want to check if a given type T is either derived from boost::in_place_factory. It doesn't have to be very strict: it can get false negative on multiple inheritance; it can give a false positive when T is implicitly convertible to boost::in_place_factory by other means, or simply return false_type when boost::in_place_factory is incomplete.
Perhaps there is a C++03-compatible solution to this particular problem?
Actually, I do not even need a true-false answer; I just need to disable an overload (in SFINAE sense) if boost::in_place_factory is either incomplete or not a base class of T.
If in_place_factory had a member void tag then you don't even need it forward declared: // in_place_factory.hpp class in_place_factory_base { public: typedef void _is_in_place_factory; }; // optional.hpp template< typename T > class optional { public: template< typename U > optional(U&& in_place, typename enable_if_has_type< typename U::_is_in_place_factory, int >::type = 0); };
2016-03-03 23:18 GMT+01:00 Daniel Frey
On 03.03.2016, at 22:57, Andrzej Krzemienski
wrote: The Standard ([meta.rel]) requires that in std::is_base_of D must be a complete type, but it does not require the same of B. This makes sense, because if we compare a complete type D and an incomplete type B, the former is surely not derived from the latter. In contrast, boost::is_base_of imposes an additional constraint that B must also be complete. Could this restriction be lifted?
That would probably be possible for all modern compilers that have a proper std::is_base_of because it requires a compiler intrinsic (unless you can implement it without such an intrinsic and in C++98). Boost.TypeTraits have quite a history and by lifting the restriction, you would drop support for old compilers (think pre-C++11).
And if you really need this feature, why not use std::is_base_of directly? Either your compiler has it or it can’t be implemented AFAICT.
I need it for patching boost::optional. It must work on any system. I do
not know how to portably check if a given compiler defines std::is_base_of.
What I do not understand now is why the following small program compiles:
http://melpon.org/wandbox/permlink/2RCFt448BwwKcwob
I also paste it here
```
#include
participants (8)
-
Andrey Semashev
-
Andrzej Krzemienski
-
Daniel Frey
-
Gavin Lambert
-
John Maddock
-
Matt Calabrese
-
Michael Caisse
-
Peter Dimov