Why result of std::size not compile time OR is not size_t?

305 Views Asked by At

On Visual C++ 2019:

The following code renders the warning:

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

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

But using _countof(events) won't give any warning. Note that std::size's template overload function is called. This one:

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

Which essentially is returning a size_t, and the function is constexpr. And that's why array declaration works:

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

But following code won't compile without warning:

DWORD sz1 = std::size(Events);

This is okay:

DWORD sz2= _countof(Events);

Any specific reason, or a compiler bug?

Relevant: What is the return type of sizeof operator?

EDIT, Interestingly, these would also work fine:

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

The variables s1 and s2 are taken as true compile-time values, but not std::size()'s result itself!

2

There are 2 best solutions below

4
On

DWORD is always 32-bit unsigned on Windows.

size_t is typically a 64-bit unsigned long long with a 64-bit compiler. Switch your build to 32-bit and it's a 32-bit unsigned int.

Assigning a 64-bit int to a 32-bit - yep, that's a warning condition.

What's weird is this:

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

Compiles without issue. I'm guessing it's because the compiler can infer the type of that const expression reduces to unsigned int or smaller.

But this:

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

Generates a nearly identical warning since count evaluates to a 64-bit unsigned long long.

But this will also compile without warning:

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

If you read the warning messages it's a complaint about converting from the type size_t (the result of std::size(Events)) to DWORD (the type of sz1).

The problem is that on a 64-bit system size_t is typically a 64-bit unsigned integer type. But Windows define DWORD as a 32 bit unsigned integer type.

That the use of _countof doesn't generate a warning might be because of implementation-specific behavior of the MSVC compiler.