Am 2024-03-26 18:50, schrieb Andrey Semashev via Boost:
On 3/26/24 18:53, Tobias Loew via Boost wrote:
Am 2024-03-25 11:38, schrieb Andrey Semashev via Boost:
I don't really like the idea of operators in the global namespace. I would rather prefer if the operators were defined in the library's namespace, and the enablement was always through the macro. Where the macro would not just import the operators for lookup but also "enable" them for the given enum.
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. 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. 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.
Additionally, there are macros to easily import all operators/utility functions into a namespace (BOOST_FLAGS_USING_OPERATORS(), BOOST_FLAGS_USING_UTILITIES()).
I'm not sure what you mean by your last sentence. Do you just ask for a macro, like
#define BOOST_FLAGS_ENABLE(Enum) \ constexpr inline bool boost_flags_enable(Enum) { return true; } \ BOOST_FLAGS_USING_OPERATORS()
or something else?
Yes, or something equivalent. I'm not sure this can be made working in all contexts, e.g. for enums declared in user's namespaces as well as in classes and templates, so there may be multiple such macros for different use cases or there may be optional arguments or something. But the effect should be the same - you apply one macro to the enum, and that makes bitwise operators work for that enum.
I'm not sure what would be the purpose of the other macros you mention (BOOST_FLAGS_USING_OPERATORS, BOOST_FLAGS_USING_UTILITIES). I mean, is there a use case for importing the operators but not enabling them? And what are the utilities and why one would want a macro to import them?
I though it the other way around: enabling without importing. When everything is imported into global namespace by default, then it's only under certain conditions (e.g. the one you pointed out) necessary to also import into the enum's 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.