This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]