Why does this program fail to compile when the error is unreachable?
I am making a class for variable bit size pixel color values. Anyway, I got it working, but there is something weird:
#pragma pack(push, 1)
template <typename my_type>
struct c {
my_type x;
c() {}
c(my_type x) { this->x = x; }
template<typename target_type>
c<target_type> convert() {
if (std::is_same<my_type, target_type>::value) {
return *this; //<- doesn't work
return *reinterpret_cast<c<target_type>*>(this); //<- does work
}
int target_size = sizeof(((c<target_type>*)0)->x);
int my_size = sizeof(x);
if (my_size < target_size) {
return c<target_type>(x << (target_size - my_size) * 8);
}
my_type rounder = ((x >> (my_size - target_size) * 8 - 1) & 9) > 4;
return c<target_type>((x >> (my_size - target_size) * 8) + rounder);
}
};
#pragma pack(pop)
on the marked line, I would have to return only * this, but if I do it and try to compile with the following test:
c<uint8_t> a;
c<uint32_t> b(2147483647);
a = b.convert<uint8_t>();
then i get error
cannot convert from c<uint32_t> to c<uint8_t>
which doesn't make sense because it shouldn't convert anything if it's the same type, which doesn't matter from uint32_t
touint8_t
This is on MSVC, does anyone know why this is happening?
source to share
In your case, when you do:
if (std::is_same<my_type, target_type>::value) {
return *this;
}
my_type
- uint32_t
, a target_type
- uint8_t
. So, std::is_same<my_type, target_type>::value
- false
, therefore return *this;
will not be executed.
However, it will compile ! And the compiler reports an error because you definitely cannot return *this
(type c<uint32_t>
) in the function that is supposed to return c<uint8_t>
as they are different types ...
Every path to your template function must be valid for compilation, even if some of them are protected from execution execution ...
source to share
In this case, you need two versions of the function, one for the same type and one for other types. One of the possibilities:
template<typename target_type>
typename std::enable_if<std::is_same<my_type, target_type>::value, c<target_type> >::type
convert() {
return *this;
}
template<typename target_type>
typename std::enable_if<!std::is_same<my_type, target_type>::value, c<target_type> >::type
convert() {
int target_size = sizeof(((c<target_type>*)0)->x);
int my_size = sizeof(x);
if (my_size < target_size) {
return c<target_type>(x << (target_size - my_size) * 8);
}
my_type rounder = ((x >> (my_size - target_size) * 8 - 1) & 9) > 4;
return c<target_type>((x >> (my_size - target_size) * 8) + rounder);
}
How it works: std::enable_if
turns on the first function in the case when the types are the same, and the other function in all other cases when the types are not the same.
source to share