什么特征使 uninitialized_copy(_n) 可以被 copy(_n) 取代?

What trait makes uninitialized_copy(_n) sustituable by copy(_n)?

我正在尝试理解类型属性和支持的操作的含义,https://en.cppreference.com/w/cpp/types

我有一个库,它实现了类似于 std::copy_n 的低级功能,当然我也必须实现 uninitialized_copy,但是对于许多类型,它们是在某种意义上微不足道,我不想重复代码并将一个委托给另一个。

什么 属性 使得 uninitialized_copy(_n) 在语义上可以被 copy(_n) 替代?

我的猜测是 std::is_trivially_default_constructible<T>::value,但我不确定。 理由是,如果某些东西是微不足道的默认可构造的,我可以跳过赋值前的初始化。

(最初我以为它可能是std::is_trivially_assignable<TSource, T>::value

当然我可以稳妥地要求std::is_trivial<T>::value,但我想更有针对性。 我知道这些特征可能有马基雅维利或误导性的定义,但假设我想相信它们。


示例代码:

template<class... As, class... Bs>
auto uninitialized_copy_n(
    my_iterator<As...>   first, Size count,
    my_iterator<Bs...> d_first
)-> my_iterator<Bs...> {
    using T1 = typename my_iterator<As...>::value_type;
    using T2 = typename my_iterator<Bs...>::value_type;
    if constexpr(std::is_trivially_constructible<T2>::value){
        return copy_n(first, count, d_first);
    }
    ... another implementation or abort 
}

要用copy替换uninitialized_copy,这两个动作必须等价:

  • uninitialized_copy:从Source
  • 类型的对象构造一个Destination类型的新对象
  • copy:假设存在一个 Destination 类型的对象,并从 Source
  • 类型的对象分配给它

必须对类型提出足够的要求,以便目标对象存在并且构造和赋值给出相同的值。

is_trivially_default_constructible 既不需要也不足以假设对象存在于内存位置。相反,目标类型必须是 implicit lifetime type。这不是递归条件,所以我们必须要求类型是隐式生命周期类型,并且递归地所有成员或子对象都是隐式生命周期类型。

例如,具有普通默认构造函数和普通析构函数的标量或 类 将起作用。

其次,我们需要构造和赋值来给出相同的结果。如果这些操作不是微不足道的,这是不可能的。但在 C++ 中,对象的值只能通过此类操作才能保证不变,这些操作适用于平凡可复制的类型,将值与表示相关联。因此,我们可能希望目的地可以轻松复制。

这给了我们:

  • std::is_trivially_default_constructible_v<Destination>
  • std::is_trivially_destructible_v<Destination>
  • std::is_trivially_constructible_v<Destination, const Source&>
  • std::is_trivially_assignable_v<Destination&, const Source&>
  • std::is_trivially_copyable_v<Destination>

这简化为:

  • std::is_trivial_v<Destination>
  • std::is_trivially_constructible_v<Destination, const Source&>
  • std::is_trivially_assignable_v<Destination&, const Source&>

注意libstdc++ requires both types to be trivial and the Destination assignable and constructible from the Source。评论引用了范围算法的一个稍微不同的条件。

libstdc++ 要求存在明显差异。参见 this examplevalue 应该是 1 (来自构造)但正在填充 2 (来自分配)。我找不到任何授予实现方式不同的许可。

libstdc++ 逻辑是最近 found to be buggy 并且可能仍然是。