C++ - 无符号长长整型向有符号长长整型的隐式转换?

3

我遇到了一个相当奇怪的警告,由clang-tidy 12.0.1报告。在下面的代码中:

#include <vector>

int main()
{
    std::vector<int> v1;

    const auto a = v1.begin() + v1.size();

    return 0;
}

我看到这个警告被触发:

error: narrowing conversion from 'std::vector<int>::size_type' (aka 'unsigned long long') to signed type 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>::difference_type' (aka 'long long') is implementation-defined [bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions,-warnings-as-errors]
    const auto a = v1.begin() + v1.size();
                                ^

据我理解,当操作两个大小相同但符号不同的整数时,有符号整数会被转换为无符号整数,而不是反过来。我是否有所遗漏?


2
你这里不是在操作两个整数。你正在将一个无符号整数参数传递给有符号整数函数参数。 - Evg
@Evg 我用一个更简洁的例子编辑了我的问题。你指的是哪个函数? - Martin
有符号溢出是未定义行为。 - Sergey Kolesnik
3
Evg 的意思是你正在调用 "iterator::operator+(long long)",其中 "long long" 是迭代器的差分类型。因此,你的 std::size_t 会被隐式转换为有符号长整型,导致 clang tidy 发出警告。 - Pepijn Kramer
2个回答

5
自 C++20 起,一个简单的解决方法是使用 std::ssize
const auto a = v1.begin() + std::ssize(v1);

1
或者使用v1.end(). ;) - Evg

3
展示涉及的实际数据类型:
// Operator+ accepts difference type
// https://en.cppreference.com/w/cpp/iterator/move_iterator/operator_arith
// constexpr move_iterator operator+( difference_type n ) const;

#include <type_traits>
#include <vector>
#include <iterator>

int main()
{
    std::vector<int> v1;

    auto a = v1.begin();
    auto d = v1.size();

    // the difference type for the iterator is a "long long"
    static_assert(std::is_same_v<long long, decltype(a)::difference_type>);

    // the type for size is not the same as the difference type
    static_assert(!std::is_same_v<decltype(d), decltype(a)::difference_type>);
    
    // it is std::size_t
    static_assert(std::is_same_v<decltype(d), std::size_t>);
    
    return 0;
}

1
明白了。令人惊奇的是,C++ 可以将最简单的任务变成复杂的噩梦。 - Martin
1
如果你认为这是一场噩梦,那么你还没有接触过初始化。;) 另一方面,规则在大多数情况下相当清晰,并且可以查阅。我认为这是一种可以实现非常高级抽象的语言,在需要时可以获得低级控制,并且可以获得确定性行为(如果你避免了未定义行为)。 - Pepijn Kramer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接