2017-06-10 2 views
3

Ich mache eine Klasse für variable Bitgröße Pixel Farbwerte. Wie auch immer, ich habe es funktioniert, aber es ist etwas Merkwürdiges:Warum kann dieses Programm nicht kompiliert werden, wenn der Fehler nicht erreichbar ist?

#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) 

auf der Linie I gekennzeichnet sind, sollte ich in der Lage sein, nur zurückkehren * dies aber wenn ich das tun und versuchen, mit dem folgenden Test zu kompilieren:

c<uint8_t> a; 
c<uint32_t> b(2147483647); 
a = b.convert<uint8_t>(); 

dann erhalte ich die Fehler

cannot convert from c<uint32_t> to c<uint8_t> 

was keinen Sinn macht, weil es nicht soll nichts, wenn seine vom gleichen Typ konvertieren, die mit uint32_t-nicht der Fall ist

Dies ist auf MSVC, weiß jemand, warum das passiert?

+0

'kann nicht von c zu c ' Nun, können Sie nicht, was ist eigentlich unklar? –

+0

Haben Sie wirklich zwei Returns hintereinander in Ihrer 'if' Anweisung oder ist das ein armer Kommentar? – erip

+0

@ πάνταῥεῖ das Szenario kann nie passieren – user81993

Antwort

4

In Ihrem Fall, wenn Sie das tun:

if (std::is_same<my_type, target_type>::value) { 
    return *this; 
} 

my_typeuint32_t und target_type ist uint8_t. Also, std::is_same<my_type, target_type>::value ist false, also return *this; wird nicht ausgeführt.

Es wird jedoch kompiliert! Und der Compiler meldet einen Fehler, denn man kann definitiv nicht zurückkehren *this (Typ c<uint32_t>), in einer Funktion sollte ein c<uint8_t> zurückzukehren, da sie unterschiedliche Typen sind ...

Jeder Pfad Ihrer Template-Funktion muss gültig sein zum Kompilieren, auch wenn ein Teil davon gegen Laufzeitausführung geschützt ist ...

+0

Ich wurde mehrmals von diesem gebissen. ['std :: enable_if'] (http://en.cppreference.com/w/cpp/types/enable_if) war meine erste Wahl, auch wenn es vielleicht bessere gibt. – Rook

+0

@Rook: Ich habe das nicht erwähnt, weil ich nicht sicher bin, wie das für dieses spezielle Problem helfen würde. – jpo38

+0

Sie können die rohe Kraft der Duplizierung der gesamten Funktion nehmen, mit einer für den speziellen Fall aktivierten Version usw. Das sollte funktionieren, denke ich. – Rook

1

In diesem Fall benötigen Sie zwei Versionen der Funktion, eine für den gleichen Typ und die andere für die anderen Typen. Eine Möglichkeit:

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);  
} 

Wie dies funktioniert, ist, dass die std::enable_if die erste Funktion im Fall ermöglicht die Typen gleich sind, und die andere Funktion in allen anderen Fällen, wenn die Typen nicht gleich ist.

Verwandte Themen