【问题标题】:Why result of std::size not compile time OR is not size_t?为什么 std::size 的结果不是编译时间或不是 size_t?
【发布时间】:2020-03-03 07:14:14
【问题描述】:

在 Visual C++ 2019 上:

以下代码呈现警告:

warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data

HANDLE events[2];
WaitForMultipleObjects(std::size(events), events, FALSE, INFINITE);

但是使用_countof(events) 不会给出任何警告。注意std::size的模板重载函数被调用了。 这个:

template<class _Ty,
    size_t _Size> inline
    constexpr size_t size(const _Ty(&)[_Size]) _NOEXCEPT
    {   // get dimension for array
    return (_Size);
    }

本质上返回一个size_t,函数是constexpr。这就是数组声明起作用的原因:

HANDLE Events[2];
int arr[std::size(Events)];

但以下代码不会在没有警告的情况下编译:

DWORD sz1 = std::size(Events);

没关系:

DWORD sz2= _countof(Events);

任何具体原因,还是编译器错误?

相关: What is the return type of sizeof operator?

编辑,有趣的是,这些也可以正常工作:

HANDLE events[2];
constexpr size_t s1 = sizeof(Events) / sizeof(Events[0]);
constexpr size_t s2 = std::size(Events);

变量s1s2 被视为真正的编译时值,而不是std::size() 的结果本身!

【问题讨论】:

  • "变量 s1 和 s2 被视为真正的编译时值,而不是 std::size() 的结果本身!" 什么是“真正的编译” -time 值,std::size() 与此有何不同?
  • @NicolBolas A constexpr 函数可能不会导致编译时常量
  • 是的,constexpr 函数可以在运行时执行。但这并没有回答我的问题:您认为什么是“真正的编译时价值”?

标签: c++ visual-c++ c++14 visual-c++-2019


【解决方案1】:

如果您阅读警告消息,这是关于将 类型 size_tstd::size(Events) 的结果) 转换为 DWORD(类型sz1)。

问题在于,在 64 位系统上,size_t 通常是 64 位无符号整数类型。但是 Windows 将 DWORD 定义为 32 位无符号整数类型。

_countof 的使用不会产生警告可能是因为 MSVC 编译器的特定于实现的行为。

【讨论】:

  • 这也没有回答我的问题。为什么 WFSO 通话中的 _countofsizeof/sizeof 可以正常工作,而 constexpr std::size() 却不行?
【解决方案2】:

DWORD 在 Windows 上始终是 32 位无符号的。

size_t 通常是带有 64 位编译器的 64 位 unsigned long long。将您的构建切换到 32 位,它是一个 32 位无符号整数。

将 64 位 int 分配给 32 位 - 是的,这是一个警告条件。

奇怪的是:

WaitForMultipleObjects(sizeof(events) / sizeof(events[0]), events, FALSE, INFINITE);

编译没有问题。我猜这是因为编译器可以推断出 const 表达式的类型减少到 unsigned int 或更小。

但是这个:

auto count = sizeof(events) / sizeof(events[0]);
WaitForMultipleObjects(count, events, FALSE, INFINITE);

生成几乎相同的警告,因为 count 的计算结果为 64 位 unsigned long long。

但这也将在没有警告的情况下编译:

const auto count = sizeof(events) / sizeof(events[0]);
WaitForMultipleObjects(count, events, FALSE, INFINITE);

【讨论】:

  • 很抱歉,它没有回答我的问题。如果sizeof(events) / sizeof(events[0]) 被放置在WFMO 调用中,它会编译得很好。 _countofARRAY_SIZE 也会。为什么不std::size
  • @Ajay - 我明白你在问什么。当我在调试器中单步执行程序集时,似乎对 std::size 的调用确实是对 &lt;xutility&gt; 中模板函数的函数调用,而不是内联。
  • 没有解释为什么它仍然需要在发布时发出警告 - 当它明确内联时。
  • constexpr 函数在这种情况下的行为类似于“consteval”。不会进行函数调用(存在基于模板的返回值解析)。让它内联与否,这是针对其他上下文的。顺便说一句,你看到 template [] 的汇编代码版本了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-19
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-16
  • 1970-01-01
相关资源
最近更新 更多