【问题标题】:C++: What is the correct cast for offseting to std::vector iterator?C++:偏移到 std::vector 迭代器的正确转换是什么?
【发布时间】:2017-06-11 05:51:26
【问题描述】:

我有一个函数接受 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);
}

这会导致 C++11 clang 编译器 -Weverything 警告集中在 + dest_offset 部分:

隐式转换将符号性:“size_t”(又名“unsigned long”)更改为“difference_type”(又名“long”)。

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

    std::copy(data, data + data_size, static_cast<double *>(dest.begin() + dest_offset));

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

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

    std::copy(data, data + data_size, &dest[dest_offset]);

这似乎消除了这种情况下的警告,但如果我尝试对源向量使用相同的模式,即使用与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());
}

+ offset 上给出相同的原始隐式转换警告。尝试使用地址索引可能会建议:

    std::copy(&data[offset], data.end(), dest.begin());

或者不同但相似的情况:

    std::copy(data.begin(), &data[offset], dest.begin());

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

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);
                                               ^

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

【问题讨论】:

  • clang 开发人员非常明确地说您应该 使用 -Weverything。
  • std::next(std::begin(), dest_offset) 有什么改变吗?

标签: c++ c++11 vector offset static-cast


【解决方案1】:

我不确定应该如何转换表达式 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)

或者从头声明dest_offset类型为difference_type的参数。

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

【讨论】:

  • 我想说参数的类型应该是std::vector&lt;double&gt;::difference_type,而不是size_t
  • std::next(dest.begin(), dest_offset) 是否避免警告?我现在没有铿锵声来测试它。
  • @Blastfurnace std::next 也需要 difference_type
  • 感谢您的回答 - 我遇到了 difference_type 我只是没有意识到它可以这样使用。我认为@n.m。可能是对的 - dest_offset 首先应该是一个差异类型。
  • 与 size_t 不同 可能会提到,为了安全/安全/无论您如何命名,代码都会检查 dest_offset ::difference_type>,例如通过使用 boost::numeric_cast 或类似方法
【解决方案2】:

您可以使用 some 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);
}

现在被广泛接受 [需要引用] 报告/使用大小和一些偏移量作为无符号整数类型是标准库设计中的一个错误。 所以在我看来,最好的办法是不要遵循这个约定,尽快从标准库中转换无符号类型,而不是让你的函数使用无符号类型。

例如copy_stuff(a.begin(), a.end(), static_cast&lt;difference_type&gt;(other.size()) )

【讨论】:

  • 谢谢,我会考虑使用这个 - 初步实验表明它确实可以让很多警告消失。
  • 你不应该检查一下dest_offset&gt;=0吗?
  • @Walter 不幸的是,认为因为类型是无符号的,它保证正值是有意义的,这是错误的。如果您输入一个负数来运行,它会将其转换为一个大的正数,这也没有意义。使用无符号类型唯一要做的就是隐藏错误。我说“不幸”是因为它具有数学意义,但实际上它不起作用,因为“无符号类型”对于“模类型”来说确实是一个坏名字。您可以添加该检查,但它有成本,最好确保程序逻辑有意义。
猜你喜欢
  • 1970-01-01
  • 2020-04-18
  • 2020-07-23
  • 1970-01-01
  • 2014-11-08
  • 2019-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多