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
