为什么我不能使用在 Visual C++ 32 位中实现运算符无符号 int() 作为数组索引的类?
Why can't I use a class which implements operator unsigned int() as an array index in Visual C++ 32-bit?
我们有一个模拟的无符号整数类型,我们称之为uint_t
,它operator unsigned int()
实现。
当我们使用这种类型的变量作为数组索引时:
#pragma warning(disable: 4514) // unreferenced inline function removed
#pragma warning(disable: 4710) // function not inlined
#pragma warning(disable: 4711) // function selected for inline expansion
#include <cstdio>
class my_uint_t
{
public:
my_uint_t(unsigned int val) { m_val = val; }
operator unsigned int() const { return m_val; }
unsigned int operator ++(int) { return m_val++; }
private:
unsigned int m_val;
};
int main(int, const char **)
{
const char *myArray[] = { "1", "2", "3", "4", "5" };
for (my_uint_t i = 0; i < sizeof(myArray)/sizeof(myArray[0]); i++)
{
printf("%sn", myArray[i]);
}
for (unsigned int i = 0; i < sizeof(myArray)/sizeof(myArray[0]); i++)
{
printf("%sn", myArray[i]);
}
return 0;
}
并在启用所有警告的情况下在Visual C++ 2015 x86中编译它,我们得到以下警告:
警告 C4365:"参数":从"无符号 int"转换为"int",有符号/无符号不匹配
根据C++语言规范(从 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf 开始(
8.2.1 下标
1 后缀表达式后跟方括号中的表达式是后缀表达式。其中之一 表达式应为"T 数组"类型的 glvalue 或 键入"指向 T 的指针",另一个应为"无作用域"的 prvalue 枚举或整型类型。结果的类型为"T"。类型"T" 应为完全定义的对象类型。66 表达式 E1[E2] 为 与 *((E1(+(E2((相同(根据定义(...
为什么 Visual C++不接受具有单个强制转换运算符的类作为"整型"unsigned int
?
注意:它对使用真正的无符号 int 的行感到满意,但对带有无符号 int 运算符的类不满意。
另请注意:这仅在 x86(32 位(版本中发生,而不是 x64。
出于好奇,我自己尝试过:
#include <iostream>
#include <vector>
struct UInt {
unsigned value;
UInt(unsigned value = 0): value(value) { }
UInt(const UInt&) = default;
operator unsigned int () const { return value; }
};
int main()
{
UInt i(2);
int a[] = { 0, 1, 2, 3, 4, 5 };
std::cout << "a[UInt(2)]: " << a[i] << 'n';
std::vector<int> v(std::begin(a), std::end(a));
std::cout << "v[UInt(2)]: " << v[i] << 'n';
return 0;
}
输出:
a[UInt(2)]: 2
v[UInt(2)]: 2
这在 coliru.com:coliru上的现场演示中进行了测试。
正如OP提到的Visual C++,我在VS2013(64位(中做了同样的测试,得到了完全相同的输出。
警告 4365 未出现。(我切换到/Wall
,并收到了大量关于std
标题的警告,这是我以前从未见过的。
请注意,我收到警告 4365 并显示以下更改:
struct UInt {
int value;
UInt(int value = 0): value(value) { }
UInt(const UInt&) = default;
operator unsigned int () const { return value; }
};
这是由operator unsigned int ()
造成的,它现在隐含地将int value
投向unsigned int
- 一个合理的警告。但是,程序会再次打印相同的输出(如预期的那样(。
按照OP的建议,我在VS2013中再次编译了上面的样本,但这次是32位。
现在,我收到数组下标a[i]
的警告 4365。
没有关于矢量下标v[i]
的抱怨。
我不确定是否值得过于认真地考虑数组下标的警告。我的意思是这是一个警告,但没有错误。
我不认为警告一般应该被忽略(他们不应该!(但在这种特定情况下......
顺便说一句。我深入挖掘了一下std::vector::operator[]
:
const
和非常量operator[]
按预期使用参数size_type
声明。我试图摆弄size_type
实际定义的位置,但我迷失在带有模板的模板中......我希望它最终是std::size_t
的 typedef(sizeof 运算符结果的无符号整数类型(。所以,当然,没有警告4365。
C 数组和原始指针的operator[]
很难检查,因为它内置在编译器中。也许,你在MSDN中问这个...
也许,在向MS发布错误报告之前,值得在VS2017中检查这一点。
共识似乎是这应该有效,因此是 x86 的 Visual C++ 编译器中的一个错误。 我已经向Microsoft报告了 https://developercommunity.visualstudio.com/content/problem/322701/cant-use-an-emulated-uint-type-as-an-array-subscri.html
我仍然在Visual Studio 2017和Visual Studio 2015中看到它。
它与 gcc 完美构建。
警告通常是无用的,但编译器可以对绝对任何事情发出无用的警告,只要它仍然接受有效的程序。
警告的无用性表示编译器错误。
请注意,32 位和 64 位版本之间没有不一致,这可以通过将unsigned int
替换为size_t
来查看。通过此更改,32 位和 64 位版本都将发出相同类型的无用警告。
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- 在 std::无符号字符的向量处存储 int 的十六进制表示形式
- 从 std::vector<无符号字符>切片中提取 int?
- 是什么导致了这种使用三进制而不是短整型的有符号int到无符号int转换
- C++无符号短裤的划分导致 int
- 将无符号转换为复杂<int>原因符号转换警告
- 如何解决隐式转换丢失整数精度:'size_t'(又名"无符号长")到'int'警告?
- 无符号的 int 到有效数字
- C++:使用没有位移位的指针将无符号字符转换为无符号 int
- 整数类型应该显式转换(例如"int"到"无符号")还是只会增加混乱?
- 有没有办法在C++中将mpz_t转换为 int 或无符号长 int?
- 是否可以将无符号 int 的最大值转换为 int 并将结果转换为 -1?
- 为什么QByteArray的大小是"int"而不是"无符号int"
- 为什么 (-i) 的类型(其中 i 是无符号的 int)仍然是无符号的 int?
- 无符号长整型和无符号 int 之间有什么区别,这 2 种类型应该如何在 c# 中封送?
- 如何对无符号长 int 进行位掩码?
- 使用无符号int作为二进制来在c++中实现一个集
- 这个右移是如何工作的:字符串流>>无符号的int>>无符号的int?
- 转换 int -> 无符号长 长 是否由标准定义
- 为什么在执行 int / 无符号 int 除法时使用 'divl'