On 3/27/24 17:01, Tobias Loew via Boost wrote:
Am 2024-03-26 18:50, schrieb Andrey Semashev via Boost:
On 3/26/24 18:53, Tobias Loew via Boost wrote:
The library now has a macro-option to prevent importing all operators into the global namespace (BOOST_FLAGS_NO_GLOBAL_USING).
I think the no-global-namespace should be the only option, and there should be no such macro. Otherwise, there is risk of configuration mismatch and ODR violations.
Enums are often used in library interfaces, and offering this configuration macro may pose a problem. For example, if a library A wants to define its public enums with this macro defined, and its user B wants to define its own enums without this macro then there will be a compatibility issue.
Thanks for pointing out this, even though I cannot see ODR violations: the definition of the operators/utility functions are always the same and reside in namespace boost::flags, the import into other namespaces is done via using declarations which (IIRC) are irrelevant to ODR.
It may be relevant to ODR if the using-declaration changes the operator found by name lookup.
One more word to, why I imported everything into global namespaces: I wanted the opt-in be a single definition and NOT a macro (just to prove, that it's possible). So, to make it work, I had to import all operators/functions into global namespace.
I understand. But being able to do it doesn't necessarily make it the best solution. Introducing things in global namespace is rather intrusive, and it has bitten us in the back in the past. I think, libraries should avoid putting their stuff in the global namespace at all costs, and the "enable" macro approach seems like an acceptable alternative to me.
From my perspective, this library is more like a core-language extension: it introduces flags to the language in a generic way, and therefore enhances the global operators with the respective functionality for enabled enums.
Even core language extension libraries should avoid polluting the global namespace. Take existing Boost libraries for example: Boost.ForEach, Boost.Lambda2, Boost.StaticAssert. By the way, we already have boost/detail/bitmask.hpp that provides bitwise operators for enums, and it is also designed to be used in the enum's namespace (i.e. without polluting the global namespace).
The utilities are a bunch of functions - for handling flags as a multi-dim Boolean algebra: tests for inclusion, intersection - easy interface for modifying flags depending on a bool, e.g. make_if(E e, bool set) for set ? e : E{} remove_if(E e, E mod, bool remove) for remove ? e & ~mod : e
I see them as part of the flags interface, so in my original version of the library they were always imported into global namespace. But I wanted the import to be optional, in case others see it different.
This sounds more like a collection of algorithms on enums. In this case, I think, they are better placed in Boost.Flags namespace, and there is no need to import them, other than to omit the namespace when calling them.