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

Jonathan Wakely jwakely@redhat.com
Thu Jan 14 19:06:00 GMT 2016


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.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch.txt
Type: text/x-patch
Size: 50927 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20160114/feadafd0/attachment.bin>


More information about the Libstdc++ mailing list