为什么 ranges::unique_copy 不能与 std::ostream_iterator 一起使用?

Why ranges::unique_copy cannot work with std::ostream_iterator?

[alg.unique], the signature of ranges::unique_copy中定义为:

template<input_­iterator I, sentinel_­for<I> S, weakly_­incrementable O, class Proj = identity,
         indirect_­equivalence_­relation<projected<I, Proj>> C = ranges::equal_to>
  requires indirectly_­copyable<I, O> &&
           (forward_­iterator<I> ||
            (input_­iterator<O> && same_­as<iter_value_t<I>, iter_value_t<O>>) ||
            indirectly_­copyable_­storable<I, O>)
  constexpr ranges::unique_copy_result<I, O>
    ranges::unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});

但是我发现当I只是一个input_iteratorO只是一个output_iterator时,下面的代码无法编译:

std::istringstream str("42 42 42");
std::ranges::unique_copy(
  std::istream_iterator<int>(str), 
  std::istream_iterator<int>(),
  std::ostream_iterator<int>(std::cout, " "));

gcc 和 msvc 都拒绝它 (godbolt):

error: no type named 'value_type' in 'using type = struct std::indirectly_readable_traits<std::ostream_iterator<int> >' {aka 'struct std::indirectly_readable_traits<std::ostream_iterator<int> >'}
 1436 |                            && same_as<iter_value_t<_Iter>, iter_value_t<_Out>>)

奇怪的是,这里的报错信息并没有显示constraints not satisfied,只是在实例化same_as<iter_value_t<_Iter>, iter_value_t<_Out>时抱怨indirectly_readable_traits<ostream_iterator<int>>中没有value_type

为什么上面的代码在 C++20 中格式错误?

这是两个实现中的错误。两者都包含相当于

if constexpr (input_­iterator<O> && same_­as<iter_value_t<I>, iter_value_t<O>>) 

在约束中这很好,因为约束满足度是通过短路逐步检查的(并且在任何情况下替换失败只会导致约束评估为 false),因此如果 O 是对于输入迭代器,我们不会询问它的(可能不存在的)值类型。在 if constexpr 中没有短路,因此整个表达式被替换为并且当场不正确。