This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++23 status.

3519. Incomplete synopses for <random> classes

Section: 28.5.4 [rand.eng], 28.5.5 [rand.adapt], 28.5.9 [rand.dist] Status: C++23 Submitter: Jens Maurer Opened: 2021-02-02 Last modified: 2023-11-22

Priority: 3

View all other issues in [rand.eng].

View all issues with C++23 status.

Discussion:

The synopses for the engine and distribution classes in <random> do not show declarations operator==, operator!=, operator<<, and operator>>, although they are part of the engine and distribution requirements.

Suggested resolution:

Add these operators as hidden friends to the respective class synopses.

[2021-02-07: Daniel provides concrete wording]

The proposed wording attempts to use a conservative approach in regard to exception specifications. Albeit 28.5.4.1 [rand.eng.general] p3 says that "no function described in 28.5.4 [rand.eng] throws an exception" (unless specified otherwise), not all implementations have marked the equality operators as noexcept (But some do for their engines, such as VS 2019). [No implementations marks the IO stream operators as noexcept of-course, because these cannot be prevented to throw exceptions in general by design].

The wording also uses hidden friends of the IO streaming operators ("inserters and extractors") as suggested by the issue discussion, but it should be noted that at least some existing implementations use out-of-class free function templates for their distributions.

Note that we intentionally don't declare any operator!=, because the auto-generated form already has the right semantics. The wording also covers the engine adaptor class templates because similar requirements apply to them.

[2021-03-12; Reflector poll]

Set priority to 3 following reflector poll.

[2021-03-12; LWG telecon]

Set status to Tentatively Ready after discussion and poll.

FAN
1000

[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4878.

  1. Modify 28.5.4.2 [rand.eng.lcong] as indicated:

    template<class UIntType, UIntType a, UIntType c, UIntType m>
    class linear_congruential_engine {
      […]
      // constructors and seeding functions
      […]
      
      // equality operators
      friend bool operator==(const linear_congruential_engine& x, const linear_congruential_engine& y);
    
      // generating functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const linear_congruential_engine& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, linear_congruential_engine& x);
    };
    
  2. Modify 28.5.4.3 [rand.eng.mers] as indicated:

    template<class UIntType, size_t w, size_t n, size_t m, size_t r,
                UIntType a, size_t u, UIntType d, size_t s,
                UIntType b, size_t t,
                UIntType c, size_t l, UIntType f>
    class mersenne_twister_engine {
      […]
      // constructors and seeding functions
      […]
      
      // equality operators
      friend bool operator==(const mersenne_twister_engine& x, const mersenne_twister_engine& y);
    
      // generating functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const mersenne_twister_engine& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, mersenne_twister_engine& x);
    };
    
  3. Modify 28.5.4.4 [rand.eng.sub] as indicated:

    template<class UIntType, size_t w, size_t s, size_t r>
    class subtract_with_carry_engine {
      […]
      // constructors and seeding functions
      […]
      
      // equality operators
      friend bool operator==(const subtract_with_carry_engine& x, const subtract_with_carry_engine& y);
    
      // generating functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const subtract_with_carry_engine& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, subtract_with_carry_engine& x);
    };
    
  4. Modify 28.5.5.2 [rand.adapt.disc] as indicated:

    template<class Engine, size_t p, size_t r>
    class discard_block_engine {
      […]
      // constructors and seeding functions
      […]
      
      // equality operators
      friend bool operator==(const discard_block_engine& x, const discard_block_engine& y);
    
      // generating functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const discard_block_engine& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, discard_block_engine& x);
    };
    
  5. Modify 28.5.5.3 [rand.adapt.ibits] as indicated:

    template<class Engine, size_t w, class UIntType>
    class independent_bits_engine {
      […]
      // constructors and seeding functions
      […]
      
      // equality operators
      friend bool operator==(const independent_bits_engine& x, const independent_bits_engine& y);
    
      // generating functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const independent_bits_engine& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, independent_bits_engine& x);
    };
    
  6. Modify 28.5.5.4 [rand.adapt.shuf] as indicated:

    template<class Engine, size_t k>
    class shuffle_order_engine {
      […]
      // constructors and seeding functions
      […]
      
      // equality operators
      friend bool operator==(const shuffle_order_engine& x, const shuffle_order_engine& y);
    
      // generating functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const shuffle_order_engine& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, shuffle_order_engine& x);
    };
    
  7. Modify 28.5.9.2.1 [rand.dist.uni.int] as indicated:

    template<class IntType = int>
    class uniform_int_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const uniform_int_distribution& x, const uniform_int_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const uniform_int_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, uniform_int_distribution& x);
    };
    
  8. Modify 28.5.9.2.2 [rand.dist.uni.real] as indicated:

    template<class RealType = double>
    class uniform_real_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const uniform_real_distribution& x, const uniform_real_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const uniform_real_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, uniform_real_distribution& x);
    };
    
  9. Modify 28.5.9.3.1 [rand.dist.bern.bernoulli] as indicated:

    class bernoulli_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const bernoulli_distribution& x, const bernoulli_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const bernoulli_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, bernoulli_distribution& x);
    };
    
  10. Modify 28.5.9.3.2 [rand.dist.bern.bin] as indicated:

    template<class IntType = int>
    class binomial_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const binomial_distribution& x, const binomial_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const binomial_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, binomial_distribution& x);
    };
    
  11. Modify 28.5.9.3.3 [rand.dist.bern.geo] as indicated:

    template<class IntType = int>
    class geometric_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const geometric_distribution& x, const geometric_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const geometric_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, geometric_distribution& x);
    };
    
  12. Modify 28.5.9.3.4 [rand.dist.bern.negbin] as indicated:

    template<class IntType = int>
    class negative_binomial_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const negative_binomial_distribution& x, const negative_binomial_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const negative_binomial_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, negative_binomial_distribution& x);
    };
    
  13. Modify 28.5.9.4.1 [rand.dist.pois.poisson] as indicated:

    template<class IntType = int>
    class poisson_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const poisson_distribution& x, const poisson_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const poisson_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, poisson_distribution& x);
    };
    
  14. Modify 28.5.9.4.2 [rand.dist.pois.exp] as indicated:

    template<class RealType = double>
    class exponential_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const exponential_distribution& x, const exponential_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const exponential_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, exponential_distribution& x);
    };
    
  15. Modify 28.5.9.4.3 [rand.dist.pois.gamma] as indicated:

    template<class RealType = double>
    class gamma_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const gamma_distribution& x, const gamma_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const gamma_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, gamma_distribution& x);
    };
    
  16. Modify 28.5.9.4.4 [rand.dist.pois.weibull] as indicated:

    template<class RealType = double>
    class weibull_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const weibull_distribution& x, const weibull_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const weibull_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, weibull_distribution& x);
    };
    
  17. Modify 28.5.9.4.5 [rand.dist.pois.extreme] as indicated:

    template<class RealType = double>
    class extreme_value_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const extreme_value_distribution& x, const extreme_value_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const extreme_value_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, extreme_value_distribution& x);
    };
    
  18. Modify 28.5.9.5.1 [rand.dist.norm.normal] as indicated:

    template<class RealType = double>
    class normal_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const normal_distribution& x, const normal_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const normal_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, normal_distribution& x);
    };
    
  19. Modify 28.5.9.5.2 [rand.dist.norm.lognormal] as indicated:

    template<class RealType = double>
    class lognormal_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const lognormal_distribution& x, const lognormal_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const lognormal_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, lognormal_distribution& x);
    };
    
  20. Modify 28.5.9.5.3 [rand.dist.norm.chisq] as indicated:

    template<class RealType = double>
    class chi_squared_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const chi_squared_distribution& x, const chi_squared_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const chi_squared_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, chi_squared_distribution& x);
    };
    
  21. Modify 28.5.9.5.4 [rand.dist.norm.cauchy] as indicated:

    template<class RealType = double>
    class cauchy_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const cauchy_distribution& x, const cauchy_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const cauchy_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, cauchy_distribution& x);
    };
    
  22. Modify 28.5.9.5.5 [rand.dist.norm.f] as indicated:

    template<class RealType = double>
    class fisher_f_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const fisher_f_distribution& x, const fisher_f_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const fisher_f_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, fisher_f_distribution& x);
    };
    
  23. Modify 28.5.9.5.6 [rand.dist.norm.t] as indicated:

    template<class RealType = double>
    class student_t_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const student_t_distribution& x, const student_t_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const student_t_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, student_t_distribution& x);
    };
    
  24. Modify 28.5.9.6.1 [rand.dist.samp.discrete] as indicated:

    template<class IntType = int>
    class discrete_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const discrete_distribution& x, const discrete_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const discrete_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, discrete_distribution& x);
    };
    
  25. Modify 28.5.9.6.2 [rand.dist.samp.pconst] as indicated:

    template<class RealType = double>
    class piecewise_constant_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const piecewise_constant_distribution& x, const piecewise_constant_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const piecewise_constant_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, piecewise_constant_distribution& x);
    };
    
  26. Modify 28.5.9.6.3 [rand.dist.samp.plinear] as indicated:

    template<class RealType = double>
    class piecewise_linear_distribution {
      […]
      // constructors and reset functions
      […]
      
      // equality operators
      friend bool operator==(const piecewise_linear_distribution& x, const piecewise_linear_distribution& y);
    
      // generating functions
      […]
      
      // property functions
      […]
      
      // inserters and extractors
      template<class charT, class traits>
        friend basic_ostream<charT, traits>&
          operator<<(basic_ostream<charT, traits>& os, const piecewise_linear_distribution& x);
      template<class charT, class traits>
        friend basic_istream<charT, traits>&
          operator>>(basic_istream<charT, traits>& is, piecewise_linear_distribution& x);
    };