[patch] libstdc++/69240 generic operator!= for random number distributions

Marc Glisse marc.glisse@inria.fr
Thu Jan 14 19:13:00 GMT 2016


On Thu, 14 Jan 2016, Jonathan Wakely wrote:

> How do people feel about this approach to solving PR 69240?
>
> The bug is that we don't define operator!= for RND::param_type, where
> RND is any of random number distributions in <random> or <ext/random>.
> Rather than tediously defining it for every param_type I've added
> this:
>
> namespace __random_not_eq
> {
>   // Derive from this tag to define l != r as !(l == r).
>   struct __tag { };
>
>   /// Compare the parameters of two random number distributions.
>   template<typename _Tp>
>     inline bool
>     operator!=(const _Tp& __lhs, const _Tp& __rhs) noexcept
>     { return !(__lhs == __rhs); }
> }
>
> Then made the param types derive from the tag:
>
>     /** Parameter type. */
>     struct param_type : private __random_not_eq::__tag
>
> This makes std::__random_not_eq an associated namespace of the
> param_type, and so the generic operator!= is found by ADL, solving the
> bug with a single operator!= function template.
>
> There's no requirement that operator!= be defined for each param_type,
> or be visible in namespace std. All that's required is that the types
> are comparable with == and != and with this technique that works,
> thanks to the magic of ADL.
>
> We can also use __random_not_eq::__tag for the distributions
> themselves, allowing us remove the operator!= overloads defined for
> every distribution type:
>
> template<typename _RealType = double>
>   class normal_distribution : private __random_not_eq::__tag
>
> I've then taken the idea one step further and defined a generic
> operator== as well:
>
> namespace __random_eq
> {
>   // Derive from this tag to define l == r as l.param() == r.param()
>   // and l != r as !(l == r).
>   struct __tag { };
>
>   /// Compare the parameters of two random number distributions.
>   template<typename _Tp>
>     inline bool
>     operator==(const _Tp& __lhs, const _Tp& __rhs) noexcept
>     { return __lhs.param() == __rhs.param(); }
> }
>
> This can be used by any distribution for which equality is defined
> simply in terms of parameter equality, allowing us to remove 14 boring
> operator== overloads that just do __d1._M_param == __d2._M_param.
>
> If this approach looks worringly like std::rel_ops then fear not. This
> way of doing it is much safer, because the generic operators are never
> brought into namespace std (or any other namespace) with "using". They
> can only be found by ADL by making __random_not_eq and/or __random_eq
> an associated namespace.
>
> This patch is missing tests so isn't ready to commit, but I want to
> know if anyone will freak out at this use of ADL. I think fixing a bug
> in dozens of classes while *removing* hundreds of lines of code is
> pretty cool.

I didn't think about it much, but I am worried that __random_not_eq will 
accidentally become an associated namespace for more classes than we would 
expect.

-- 
Marc Glisse



More information about the Libstdc++ mailing list