C++ STL 向量:使用 `-Wsign-conversion` 将 `std::size_t` 索引干净地转换为迭代器

问题描述 投票:0回答:1

使用

std::vector
时,有没有办法将
std::size_t
类型的索引转换为相应的迭代器,而在启用
-Wsign-conversion
(GCC,Clang)时不产生任何警告,最好不使用
static_cast 
?

将索引转换为迭代器的标准方法似乎假定有符号索引,因此当索引为无符号类型时会生成警告。这是相当不幸的,因为

std::vector
的自然索引类型是无符号类型,使用带符号索引的数据访问将生成符号转换警告。

作为一个激励性的例子,像

std::vector::erase
这样的方法需要一个迭代器,并且没有明显的替代方案来代替
erase
直接使用索引。

考虑以下示例:

#include <vector>
#include <iterator>

int main()
{
    std::vector<int> data{0, 1, 2, 3, 4};
    std::size_t index = 1;

    data[index]; // No warning
    const auto iterator = std::next(data.begin(), index); // Warning

    data.erase(iterator);

    return 0;
}

使用 GCC 或 Clang 编译时,使用

-Wsign-conversion
时,会生成警告:

g++ -Wsign-conversion main.cpp

main.cpp:12:55: 警告:从 'std::size_t' {aka 'long unsigned int'} 转换为 'std::__iterator_traits<__gnu_cxx::__normal_iterator, void>::difference_type' {aka 'long int'} 可能会改变结果的符号 [-Wsign-conversion]

将索引类型从

std::size_t
更改为
int
并不是一个很好的解决方案,因为数据访问 (
data[index]
) 然后会生成警告。数据访问当然是更常见的情况。

使用指针运算也无济于事,因为这也会产生符号转换警告:

const auto iterator = data.begin() + index;

起作用的是

static_cast
,尽管这几乎不可取,并且会引发有关可能的范围差异和未定义行为的问题:

const auto iterator = std::next(data.begin(), static_cast<std::ptrdiff_t>(index));

如果通过

erase
中的自然索引类型进行
std::vector
的唯一方法需要
static_cast
(启用时使符号转换警告静音),则感觉这里的 API 设计存在一个大漏洞。

c++ gcc clang stdvector compiler-warnings
1个回答
0
投票

使用指针运算也无济于事,因为这也会产生符号转换警告:

const auto iterator = data.begin() + index;

所以,如果一个人只有一把锤子,其他一切看起来都像钉子:

const auto iterator=data.begin()+static_cast<long>(index);

不再有警告。有时,碳基生命形式知道的更多,并且需要智取编译器。

© www.soinside.com 2019 - 2024. All rights reserved.