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?

+3


source to share


2 answers


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 ...

+4


source


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.

+1


source







All Articles