Feature macro for putting things in the std namespace
Hi all, I'm working on providing support in Boost for a new standard library provider, which happens to put some but not all of its symbols in the 'std' namespace. As a result, opening the 'std' namespace and forward-declaring or specializing things would not work. It seems a number of Boost libraries do this (most notably Boost.Container), with special code to deal with libc++ (since libc++ puts everything under an inline namespace). I think it would make more sense to have a BOOST_HAS_SYMBOLS_IN_STD_NAMESPACE feature macro that one could check to tell whether it is possible or not to do that. In the case of forward-declarations, the library would have to fall back to including the appropriate headers if that feature macro is not set. Is everyone on board with this? Any recommendation for the name?
El 27/08/2015 a las 22:31, Mathias Gaunard escribió:
Hi all,
I'm working on providing support in Boost for a new standard library provider, which happens to put some but not all of its symbols in the 'std' namespace.
As a result, opening the 'std' namespace and forward-declaring or specializing things would not work.
It seems a number of Boost libraries do this (most notably Boost.Container), with special code to deal with libc++ (since libc++ puts everything under an inline namespace).
I think many boosters will be against Boost.Container practice, but I would prefer fixing this supporting more standard libraries, just including headers looking for forward declarations is really heavyweight. A new standard library or new name versioning is not something that happens every day. The trick is that GCC has some namespace tricks depending on debug modes and libc++ declares some types outside the inline namespace (to be ABI compatible with GCC, like std::nothrow_t). Of course, it would be even better if we could add a std forward declaration library or utility to Boost that could be even updated with standard library maintainers that want to contribute. Best, Ion
Ion Gaztañaga
I think many boosters will be against Boost.Container practice, but I would prefer fixing this supporting more standard libraries, just including headers looking for forward declarations is really heavyweight. A new standard library or new name versioning is not something that happens every day.
As I said, the standard library in question has different symbols in different namespaces, it is not just versioning. allocator, less, char_traits, insert_iterator are in ::std::native_std, and put into std through 'using', but pair is directly in ::std. The exact behaviour possibly depends on a variety of settings as well, for example the symbols might be iin ::std::native_std::version_id, so the actual logic to deduce which symbol is defined where is not trivial. Since this is allowed by the C++ standard, I think Boost should follow the safe route here, and simply have a fallback where it includes the right headers if it doesn't know the location of each symbol. After all it's just a compile-time optimization, it's all nice and good if you want to have that optimization for libstdc++ and libc++, but it would be better to have the library at least work with other standard- conforming standard libraries rather than break because of some non- essential optimization. I actually found another thread about this subject from 2011, http://lists.boost.org/Archives/boost/2011/02/177218.php The person suggested a BOOST_NO_FWD_STD_DECLARATION feature macro as well, but that wasn't implemented. I know of the following: - most of Ion's libraries (intrusive, interprocess, container), do some std forward declaring - there is a boost/detail/container_fwd.hpp, used by boost hash, which also forwards standard containers, though it can be disabled with BOOST_DETAIL_NO_CONTAINER_FWD. - flyweight uses the following logic: if libc++, include headers, otherwise, forward-declare.
Of course, it would be even better if we could add a std forward declaration library or utility to Boost that could be even updated with standard library maintainers that want to contribute.
That would be good, but that's more work, and we're likely to get tied up in the details due to the different needs of the various boost authors, as happened in the previous thread. Therefore I suggest a feature macro that, if not defined, means that the library author should include the header rather than try to forward declare, and enforce that the various headers that do forward declarations respect it.
On 28.08.2015 13:42, Mathias Gaunard wrote:
Ion Gaztañaga
writes: I think many boosters will be against Boost.Container practice, but I would prefer fixing this supporting more standard libraries, just including headers looking for forward declarations is really heavyweight. A new standard library or new name versioning is not something that happens every day.
As I said, the standard library in question has different symbols in different namespaces, it is not just versioning. allocator, less, char_traits, insert_iterator are in ::std::native_std, and put into std through 'using', but pair is directly in ::std. The exact behaviour possibly depends on a variety of settings as well, for example the symbols might be iin ::std::native_std::version_id, so the actual logic to deduce which symbol is defined where is not trivial.
Since this is allowed by the C++ standard, I think Boost should follow the safe route here, and simply have a fallback where it includes the right headers if it doesn't know the location of each symbol.
After all it's just a compile-time optimization, it's all nice and good if you want to have that optimization for libstdc++ and libc++, but it would be better to have the library at least work with other standard- conforming standard libraries rather than break because of some non- essential optimization.
I actually found another thread about this subject from 2011, http://lists.boost.org/Archives/boost/2011/02/177218.php
The person suggested a BOOST_NO_FWD_STD_DECLARATION feature macro as well, but that wasn't implemented.
I know of the following: - most of Ion's libraries (intrusive, interprocess, container), do some std forward declaring - there is a boost/detail/container_fwd.hpp, used by boost hash, which also forwards standard containers, though it can be disabled with BOOST_DETAIL_NO_CONTAINER_FWD. - flyweight uses the following logic: if libc++, include headers, otherwise, forward-declare.
Of course, it would be even better if we could add a std forward declaration library or utility to Boost that could be even updated with standard library maintainers that want to contribute.
That would be good, but that's more work, and we're likely to get tied up in the details due to the different needs of the various boost authors, as happened in the previous thread.
Therefore I suggest a feature macro that, if not defined, means that the library author should include the header rather than try to forward declare, and enforce that the various headers that do forward declarations respect it.
I think BOOST_HAS_SYMBOLS_IN_STD_NAMESPACE, as you described it, would be mostly useless in the modern C++. libc++ already uses inline namespace and I suspect libstdc++ with gcc 5+ is also using some namespace versioning (I didn't check though). So most of the time the macro won't be defined. Then if a library author is willing to support STL implementations with namespace versioning he will have to act despite that BOOST_HAS_SYMBOLS_IN_STD_NAMESPACE is not defined and still rely on STL-specific macros to detect the implementation. This is no better than what is done currently. I agree that a better solution would be a standard forwarding library. boost/detail/container_fwd.hpp and other libraries could then be ported to it. This library then could fall back to including the STL headers and have the equivalent of BOOST_DETAIL_NO_CONTAINER_FWD. If this is too much of a work for you then I think it's better to maintain the status quo, i.e. patch the affected places to include awareness of the BSL.
Andrey Semashev
I think BOOST_HAS_SYMBOLS_IN_STD_NAMESPACE, as you described it, would be mostly useless in the modern C++. libc++ already uses inline namespace and I suspect libstdc++ with gcc 5+ is also using some namespace versioning (I didn't check though). So most of the time the macro won't be defined.
Then if a library author is willing to support STL implementations with namespace versioning he will have to act despite that BOOST_HAS_SYMBOLS_IN_STD_NAMESPACE is not defined and still rely on STL-specific macros to detect the implementation. This is no better
As soon as it happens, some Boost code here and there will break and need to be changed, since libc++ is currently the only stdlib out of the 10 supported ones that do it, and is special-cased in various places. than
what is done currently.
I agree that a better solution would be a standard forwarding library. boost/detail/container_fwd.hpp and other libraries could then be
The point of the feature macro would be to make it slightly easier on the library developer, which will not have to enumerate all library implementations that support forward-declaring things in the std namespace, namely: - libstdc++ up to a certain version - stlport - Comeau - Roguewave - SGI - Metrowerks - VACPP - Modena - Dinkumware Any other library would either have to be special cased or to include headers directly. While this is a hack and not a defect, it's supported by 90% of the supported libraries, so having a feature macro makes sense to me. I think it should be a BOOST_HAS_, rather than a BOOST_NO_, since it's not a defect, but a "feature". ported
to it. This library then could fall back to including the STL headers and have the equivalent of BOOST_DETAIL_NO_CONTAINER_FWD.
If this is too much of a work for you then I think it's better to maintain the status quo, i.e. patch the affected places to include awareness of the BSL.
This can be done in the longer term, but I think a feature macro is an easier way to solve the problem in the short term.
On 8/28/2015 7:42 AM, Mathias Gaunard wrote:
As I said, the standard library in question has different symbols in different namespaces, it is not just versioning. allocator, less, char_traits, insert_iterator are in ::std::native_std, and put into std through 'using', but pair is directly in ::std. The exact behaviour possibly depends on a variety of settings as well, for example the symbols might be iin ::std::native_std::version_id, so the actual logic to deduce which symbol is defined where is not trivial.
Since this is allowed by the C++ standard, I think Boost should follow the safe route here, and simply have a fallback where it includes the right headers if it doesn't know the location of each symbol.
If by "this" you mean defining stuff elsewhere and importing into namespace `std` via `using` then no, that is not allowed by the C++ standard. That is precisely why we have inline namespaces (with the end goal being ABI compatibility).
After all it's just a compile-time optimization, it's all nice and good if you want to have that optimization for libstdc++ and libc++, but it would be better to have the library at least work with other standard- conforming standard libraries rather than break because of some non- essential optimization.
+1. There is no standard conformant way of forward declaring stuff from the standard library after all, so there should be a fallback that just includes whatever header declares those symbols. Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Agustín K-ballo Bergé
If by "this" you mean defining stuff elsewhere and importing into namespace `std` via `using` then no, that is not allowed by the C++ standard.
Where do you see this? A lot of stuff from both libc++ and libstdc++ are also defined like this. All cXXX headers define their symbols in the global namespace, then put them into ::std with a using.
On 8/28/2015 10:50 AM, Mathias Gaunard wrote:
Agustín K-ballo Bergé
writes: If by "this" you mean defining stuff elsewhere and importing into namespace `std` via `using` then no, that is not allowed by the C++ standard.
Where do you see this?
Have a look at N1344, Namespaces and Library Versioning, where it explains that using `using` it's not an option; and at N2535, Namespace Association ("inline namespace"), where inline namespaces are proposed as a viable option to solve the issues raised in N1344.
A lot of stuff from both libc++ and libstdc++ are also defined like this.
I'd be interested in knowing which symbols are part of that lot of stuff, when those fall out of the special rules for standard library symbols.
All cXXX headers define their symbols in the global namespace, then put them into ::std with a using.
cXXX headers are not guaranteed nor required to define their symbols in the global namespace. Special wording allows those specific headers to be implemented by #including the corresponding XXX.h, which does define those symbols in the global namespace (since it's a C header), and later bring them into `std` via `using`. Refer to 17.6.1.2 [headers]/4 for the wording bits. Regards, -- Agustín K-ballo Bergé.- http://talesofcpp.fusionfenix.com
Agustín K-ballo Bergé
Have a look at N1344, Namespaces and Library Versioning, where it explains that using `using` it's not an option; and at N2535, Namespace Association ("inline namespace"), where inline namespaces are proposed as a viable option to solve the issues raised in N1344.
While those papers don't directly state it's not allowed, they do mention that struct MyClass { ... }; namespace std { template<> class vector<MyClass> { ... }; } must be well-formed. The standardese for this is C++03 17.4.3.1/1 and C++11 17.6.4.2.1. In practice I don't see how this can work if the library implements any extensions, unless those are explicitly tagged and checked every time. I wonder why this thing is even allowed, it should be limited to hash and other extension points. In which case should the BSL model, if Boost is willing to support it, be considered a defect?
participants (4)
-
Agustín K-ballo Bergé
-
Andrey Semashev
-
Ion Gaztañaga
-
Mathias Gaunard