Boost logo

Boost :

From: tobi_at_[hidden]
Date: 2024-03-27 15:53:34


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.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk