将 "enum: int64_t" 值写入 std::ostringstream 会将其截断为 int。

7

这段代码在使用MSVC编译器(v141工具集,/std:c++17)时表现出意外的行为:

#include <iostream>
#include <limits>
#include <sstream>
#include <stdint.h>

int main() {
    std::ostringstream ss;
    enum Enum : int64_t {muchos_digitos = std::numeric_limits<int64_t>::max() - 1000};
    ss << muchos_digitos;
    std::cout << ss.str();
    return 0;
}

具体来说,它打印出"-1001"。只有在启用了/W4警告级别后,我才发现了原因:

warning C4305: 'argument': truncation from 'main::Enum' to 'int'

但是为什么会这样呢?确实,调试器确认调用的是int重载,而不是long long,但是为什么呢?如何在通用代码中规避此问题?我可以将muchos_digitos转换为int64_t,但我收到的值是typename T。我可以知道它是一个枚举,但是我怎么知道它是一个强类型枚举,并且能够找到其基础类型?我认为这是不可能直接实现的... 在GCC下输出是正确的,但我需要代码能够在GCC、clang和MSVC三个编译器中运行。在线演示。附言:一开始我的项目没有设置/W4是一个错误。我建议每个人都使用这个级别来使用MSVC,使用GCC / clang的-pedantic-errors,这真的可以节省您在编写代码时处理奇怪的错误和出乎意料的行为的时间。

1
真正奇怪的是,如果我悬停在<<上,智能感应会告诉我它选择了long long重载。这一定是一个错误,但我在报告中没有找到任何相关信息。 - NathanOliver
1
不是关于“为什么”的答案,但您可以通过使用来自 https://dev59.com/sGgu5IYBdhLWcg3wTVY6 的方法以与模板兼容的方式解决此问题。 - rtpax
1
在使用C++时,最好使用标准的C++头文件,包括"C++ wrapped C"头文件,并避免使用标准的C头文件。因此,应该使用<cstdint>而不是<stdint.h> - Eljay
3
使用C++包装的C头文件将符号放置在std命名空间中,去除了一些C宏并使用C++内联函数代替,并提供了正确重载的C++版本而不是非重载的C版本,这是其合理性所在。 - Eljay
4
向MSVC提交一个错误报告。这应该会提升到底层类型。 - T.C.
显示剩余6条评论
1个回答

1

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