Reputation: 10039
Upon upgrading to MSVC 2015 (from MSVC 2013), I started getting warnings for the following code:
template< unsigned int i0, unsigned int i1, unsigned int i2, unsigned int i3 >
static __m128 Constant( )
{
static __m128i v = {
((i0&0x000000FF) >> 0 ), ((i0&0x0000FF00) >> 8), ((i0&0x00FF0000) >> 16), ((i0&0xFF000000) >> 24),
((i1&0x000000FF) >> 0 ), ((i1&0x0000FF00) >> 8), ((i1&0x00FF0000) >> 16), ((i1&0xFF000000) >> 24),
((i2&0x000000FF) >> 0 ), ((i2&0x0000FF00) >> 8), ((i2&0x00FF0000) >> 16), ((i2&0xFF000000) >> 24),
((i3&0x000000FF) >> 0 ), ((i3&0x0000FF00) >> 8), ((i3&0x00FF0000) >> 16), ((i3&0xFF000000) >> 24) };
return *(__m128*)&v;
}
Produces the following (with Constant<0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF>()
):
note: see reference to function template instantiation '__m128 Constant<2147483647,2147483647,2147483647,2147483647>(void)' being compiled
warning C4838: conversion from 'unsigned int' to 'char' requires a narrowing conversion
The __m128i
union is defined inside emmintrin.h
, as a union of arrays with several different types, which represent an MMX register. To list initialize the structure, you must use the first type declared in the union, in this case, __int8
. According to MSVC 2013 documentation (https://msdn.microsoft.com/en-us/library/29dh1w7z.aspx), __int8
maps to char
, I would assume the same for MSVC 2015. So, it seems like the warning is valid, because even though the template parameters are non-types, not all of the fields would fit into char
type after conversion.
My question is why does MSVC 2013 not give a warning for this (as it seems like a core c++11 issue)? Also, is there a 'nice' way to resolve the warning?
Upvotes: 1
Views: 1330
Reputation: 10039
@Chuck Walbourn - "Note that C4838 is new for VS 2015 which is why it doesn't come up in VS 2013."
Upvotes: 0
Reputation: 275565
Factor out the shift-mask-cast:
template<unsigned n, unsigned value>
/*constexpr*/ int8_t get_byte() {
return static_cast<int8_t>(0xFF & (value >> (n*8)));
}
Then use it:
template<unsigned i0, unsigned i1, unsigned i2, unsigned i3>
static __m128 Constant( )
{
static __m128i v = {
get_byte<0,i0>(), get_byte<1,i0>(), get_byte<2,i0>(), get_byte<3,i0>(),
get_byte<0,i1>(), get_byte<1,i1>(), get_byte<2,i1>(), get_byte<3,i1>(),
get_byte<0,i2>(), get_byte<1,i2>(), get_byte<2,i2>(), get_byte<3,i2>(),
get_byte<0,i3>(), get_byte<1,i3>(), get_byte<2,i3>(), get_byte<3,i3>(),
};
return *(__m128*)&v;
}
note that get_byte
returns a signed 8 bit integer.
Notice how the symmetry of the above is really obvious.
Upvotes: 2