Title
Bogus requirements for piecewise_linear_distribution
Status
new
Section
[rand.dist.samp.pconst] [rand.dist.samp.plinear]
Submitter
Jonathan Wakely

Created on 2024-02-04.00:00:00 last changed 2 days ago

Messages

Date: 2026-06-04.14:39:48

Proposed resolution:

This wording is relative to N5046.

  1. Modify [rand.dist.samp.pconst] as indicated:

    template<class InputIteratorB, class InputIteratorW>
      piecewise_constant_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                      InputIteratorW firstW);
    

    -4- Mandates: Both of

    1. (4.1) — is_convertible_v<iterator_traits<InputIteratorB>::value_type, result_typedouble>

    2. (4.2) — is_convertible_v<iterator_traits<InputIteratorW>::value_type, result_typedouble>

    are `true`.

    -5- Preconditions: `InputIteratorB` and `InputIteratorW` each meet the Cpp17InputIterator requirements ([input.iterators]). If firstB == lastB or ++firstB == lastB, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, [firstB, lastB) forms a sequence b of length n + 1, the length of the sequence w starting from firstW is at least n, and any wk for kn are ignored by the distribution.

    -6- Effects: Constructs a `piecewise_constant_distribution` object with parameters as specified above. calculated from the following values: If distance(firstB, lastB) is less than 2, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, let n = distance(firstB, lastB) - 1, the range [firstB, lastB) forms a sequence b and the counted range firstW+[0, n) forms a sequence w.

    template<class UnaryOperation>
      piecewise_constant_distribution(initializer_list<RealType> bl, UnaryOperation fw);
    

    -7- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

    template<class UnaryOperation>
      piecewise_constant_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
    

    -10- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

  2. Modify [rand.dist.samp.plinear] as indicated:

    template<class InputIteratorB, class InputIteratorW>
      piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                    InputIteratorW firstW);
    

    -4- Mandates: Both of

    1. (4.1) — is_convertible_v<iterator_traits<InputIteratorB>::value_type, result_typedouble>

    2. (4.2) — is_convertible_v<iterator_traits<InputIteratorW>::value_type, result_typedouble>

    are `true`.

    -5- Preconditions: `InputIteratorB` and `InputIteratorW` each meet the Cpp17InputIterator requirements ([input.iterators]). If `firstB == lastB` or `++firstB == lastB`, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, [`firstB`, `lastB`) forms a sequence b of length n + 1, the length of the sequence w starting from `firstW` is at least n + 1, and any wk for kn + 1 are ignored by the distribution.

    -6- Effects: Constructs a `piecewise_linear_distribution` object with parameters as specified above. calculated from the following values: If distance(firstB, lastB) is less than 2, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, let n = distance(firstB, lastB) - 1, the range [firstB, lastB) forms a sequence b and the counted range firstW+[0, n + 1) forms a sequence w.

    template<class UnaryOperation>
      piecewise_linear_distribution(initializer_list<RealType> bl, UnaryOperation fw);
    

    -7- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

    template<class UnaryOperation>
      piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
    

    -10- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

Date: 2026-06-15.00:00:00

[ 2026-06-03; Jonathan provides new wording ]

Date: 2025-10-15.00:00:00

[ 2025-10-06; Hewill comments and provides wording ]

We should fix the constructor, otherwise the following should be rejected according to the standard:

#include <random>

struct Op {
  float operator()(float);
  void operator()(auto) = delete;
};

static_assert(!std::is_invocable_r_v<double, Op&, double>);

int main() {
  std::initializer_list<float> l;
  std::piecewise_linear_distribution<float> dist(l, Op{});
}

This is, because it violates Mandates. However, all three compilers accept it because Op& can take `float` and return `float`.

This wording is relative to N5014.

  1. Modify [rand.dist.samp.pconst] as indicated:

    template<class InputIteratorB, class InputIteratorW>
      piecewise_constant_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                      InputIteratorW firstW);
    

    -4- Mandates: Both of

    1. (4.1) — is_convertible_v<iterator_traits<InputIteratorB>::value_type, result_typedouble>

    2. (4.2) — is_convertible_v<iterator_traits<InputIteratorW>::value_type, result_typedouble>

    are `true`.

    […]

    template<class UnaryOperation>
      piecewise_constant_distribution(initializer_list<RealType> bl, UnaryOperation fw);
    

    -7- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

    template<class UnaryOperation>
      piecewise_constant_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
    

    -10- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

  2. Modify [rand.dist.samp.plinear] as indicated:

    template<class InputIteratorB, class InputIteratorW>
      piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                    InputIteratorW firstW);
    

    -4- Mandates: Both of

    1. (4.1) — is_convertible_v<iterator_traits<InputIteratorB>::value_type, result_typedouble>

    2. (4.2) — is_convertible_v<iterator_traits<InputIteratorW>::value_type, result_typedouble>

    are `true`.

    […]

    template<class UnaryOperation>
      piecewise_linear_distribution(initializer_list<RealType> bl, UnaryOperation fw);
    

    -7- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

    template<class UnaryOperation>
      piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
    

    -10- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

Date: 2024-03-15.00:00:00

[ 2024-03-12; Reflector poll ]

Set priority to 4 after reflector poll. The copy & paste error was fixed editorially.

Date: 2024-02-05.12:51:27

In the second constructor of [rand.dist.samp.plinear], P1719R2 replaced:


template<class InputIteratorB, class InputIteratorW>
  piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                InputIteratorW firstW);

Effects: [...] Moreover, the id-expressions iterator_traits<InputIteratorB>::value_type and iterator_traits<InputIteratorW>::value_type shall each denote a type that is convertible to double.

with

template<class InputIteratorB, class InputIteratorW>
  piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                InputIteratorW firstW);

Mandates: is_invocable_r_v<double, UnaryOperation&, double> is true.

Preconditions: [...]

Effects: [...]

This was a copy & paste error from the next constructor, and was obviously not intended. There is no UnaryOperation in that constructor.

A less obviously wrong issue is the use of double there in the first place. Shouldn't it be RealType instead? That seems to be incorrect throughout both [rand.dist.samp.pconst] and [rand.dist.samp.plinear], and was only partially fixed by LWG 1439.

Finally, the preconditions also say:

Preconditions: [...] If firstB == lastB or ++firstB == lastB, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, [firstB, lastB) forms a sequence b of length n + 1, the length of the sequence w starting from firstW is at least n, and any wk for kn are ignored by the distribution.

These are not preconditions. I think it is trying to say something like:

Preconditions: [...] [firstB, lastB) is a valid range and [firstW, firstW + (lastB - firstB)) is a valid range.

Effects: If firstB == lastB or ++firstB == lastB, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, let [firstB, lastB) form a sequence b0, …, bn, and let wk = *firstW++ for k = 0, …, n.

The equivalent constructor for piecewise_constant_distribution has similar problems with its preconditions in terms of n + 1.

History
Date User Action Args
2026-06-04 14:39:48adminsetmessages: + msg16363
2025-10-11 10:14:37adminsetmessages: + msg15145
2025-10-11 10:14:37adminsetmessages: + msg15144
2024-03-12 01:17:28adminsetmessages: + msg14001
2024-02-05 12:11:19adminsetmessages: + msg13946
2024-02-05 12:11:19adminrestored
2024-02-04 17:03:55adminretired
2024-02-04 17:03:55adminsetmessages: - msg13944, msg13945
2024-02-04 15:47:01adminsetmessages: + msg13945
2024-02-04 00:00:00admincreate