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.
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.
When the operators are not imported into global namespace, enabling ADL for enums in classes is a bit of a problem, since there doesn't exist a class-local `using` declaration. So, one would either need a macro which generates friend-proxies for each operator friend constexpr local_enum operator&(local_enum l, local_enum r) { return ::boost::flags::operator&(l, r); } and so on, which add an additional indirection and defines a lot of new operators. Or a using declaration before or after the class, which is non-local. Both options don't seem really nice. At least, I found a way, to check inside the class that ADL is working. (Here to keep it short only for operator&) namespace n { using ::boost::flags::operator&; struct m { enum class local_enum { p = 1, }; friend constexpr inline bool boost_flags_enable(local_enum) { return true; } friend constexpr void boost_flags_adl_check() { static_assert([](local_enum a) { return (a = a & a, true); }(local_enum{}), ""); } }; } That way the enabling and check could be in a single macro right after the definition of the enum.