C++:偏移到 std::vector 迭代器的正确转换是什么?

dav*_*idA 5 c++ vector offset static-cast c++11

我有一个函数,它需要一个std::vector双精度,并将它们复制到另一个向量,但在一个特定的偏移量(假设有足够的空间):

void copy_stuff(const std::vector<double> & data,
                std::vector<double> & dest,
                size_t dest_offset) {
    std::copy(data.begin(), data.end(), dest.begin() + dest_offset);
}
Run Code Online (Sandbox Code Playgroud)

这会导致 C++11 clang 编译器-Weverything警告以+ dest_offset零件为中心:

隐式转换改变符号:'size_t'(又名'unsigned long')到'difference_type'(又名'long')。

我不确定应该如何转换表达式dest.begin() + dest_offset以消除此警告。将结果转换为 adouble *不会编译:

    std::copy(data, data + data_size, static_cast<double *>(dest.begin() + dest_offset));
Run Code Online (Sandbox Code Playgroud)

无法从类型“std::__1::__wrap_iter”转换为指针类型“double *”。

我曾考虑使用向量索引,然后获取地址:

    std::copy(data, data + data_size, &dest[dest_offset]);
Run Code Online (Sandbox Code Playgroud)

这似乎消除了这种情况下的警告,但如果我尝试对源向量使用相同的模式,即与std::copy. 例如:

static void copy_stuff_differently(const std::vector<double> & data,
                                   std::vector<double> & dest,
                                   size_t offset) {
    std::copy(data.begin() + offset, data.end(), dest.begin());
}
Run Code Online (Sandbox Code Playgroud)

+ offset. 尝试使用 address-of-index 可能会建议:

    std::copy(&data[offset], data.end(), dest.begin());
Run Code Online (Sandbox Code Playgroud)

或者一个不同但相似的案例:

    std::copy(data.begin(), &data[offset], dest.begin());
Run Code Online (Sandbox Code Playgroud)

但是两者都会导致类似的错误:

test.cpp:8:3: error: no matching function for call to 'copy'
  std::copy(&data[offset], data.end(), dest.begin());
  ^~~~~~~~~
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iterator:1286:48: note:
      candidate template ignored: deduced conflicting types for parameter '_Ip' ('const double *' vs.
      'std::__1::__wrap_iter<const double *>')
    template <class _Ip, class _Op> friend _Op copy(_Ip, _Ip, _Op);
                                               ^
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种一致且无警告的方法来处理此类偏移。处理向量偏移并避免此类错误和警告的正确方法是什么?

alf*_*lfC 6

您可以使用一些方法 difference_type来避免此警告:

#include<vector>

using difference_type = std::vector<double>::difference_type;
    
void copy_stuff(const std::vector<double> & data,
                std::vector<double> & dest,
//                size_t dest_offset)
                difference_type dest_offset)
{
    std::copy(data.begin(), data.end(), dest.begin() + dest_offset);
}
Run Code Online (Sandbox Code Playgroud)

如今人们普遍认为,报告/使用大小和某些偏移量作为无符号整数类型是标准库设计中的一个错误。因此,在我看来,最好是不遵循该约定并尽快从标准库中转换无符号类型,而不是调整您的函数以使用无符号类型。

例如copy_stuff(a.begin(), a.end(), static_cast<difference_type>(other.size()) )


更新 2022: C++20 ( ) 中的 Ranges 库std::ranges有一个名为 的函数std::ranges::ssize,它将给出包含的有符号整数类型的大小。这样,就可以更轻松地提取大小,并在任何后续算术运算中一致使用有符号类型。

例如copy_stuff(a.begin(), a.end(), std::ranges::ssize(other) )


son*_*yao 5

我不确定应该如何转换表达式dest.begin() + dest_offset以消除此警告。

警告只是告诉您应该dest_offset是 类型std::vector::difference_type,但它是size_t.

您可以显式进行转换以消除警告(请注意,如果源值无法在difference_type结果中表示,则是实现定义的)。例如

dest.begin() + static_cast<std::vector<double>::difference_type>(dest_offset)
Run Code Online (Sandbox Code Playgroud)

或者从一开始就dest_offset用类型声明参数difference_type

注意std::vector::difference_type是一个有符号整数类型(通常是std::ptrdiff_t),它不同于size_t;这是一个无符号整数类型。

  • 我会说参数的类型应该是 `std::vector&lt;double&gt;::difference_type` 而不是 `size_t` 开始。 (6认同)