2010-09-30 17 views
7

W tym kodzie:Dlaczego potrzebowałbym konwersji?

template<class T> 
struct Side 
{ 
}; 

template<class T> 
struct LeftSide : public Side<T> 
{ 
}; 
template<class T> 
struct RightSide : public Side<T> 
{ 
}; 

Side<int>* f(int left, int right) 
{ 
    return left < right ? new LeftSide<int> : new RightSide<int>;//<---Here I'm returning either left or right side 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    return 0; 
} 

Dostaję błąd:
_Error 1 error C2446: ':': konwersja z 'rightside *' do 'leftside *' _

I pomyślałem (błędnie, jak widzę), że mogę przypisać wskaźnik z wyprowadzonego do bazy bez żadnych problemów. Więc gdzie jest problem?

Odpowiedz

14

Problemem jest z konwersją z obu LeftSide lub RightSide do Side<T>. Jak pierwotnie sądziliście, ta konwersja byłaby w porządku.

raczej problem jest z tym wyrażeniem:

left < right ? new LeftSide<int> : new RightSide<int> 

Złammy to trochę w dół. Operator trójskładnikowych (właściwie określone w normie jako „operatora porównania”) wygląda następująco:

bool_val ? lhs_expression : rhs_expression 

Należy pamiętać, że cała ta konstrukcja jest sama w sobie wyrazem. Oznacza to, że zwraca wartość, która musi mieć typ, obv. Typ całego wyrażenia wywodzi się z typów lhs_expression i rhs_expression. W takim przypadku masz numer LeftSide i RightSide. Oto twój problem.

LeftSide i RightSide nie są bezpośrednio ze sobą powiązane, oprócz wspólnej klasy bazowej i nie ma między nimi żadnej konwersji. (Musiałbyś napisać jeden.) Więc nie ma jednego typu danych, który może mieć bool_val ? lhs_expression : rhs_expression. Możesz pomyśleć: "no, głupi kompilator, dlaczego nie po prostu wymyślić wspólną klasę bazową i użyć tego?" To jest rzeczywiście trochę uciążliwe. Pozostawiając na boku argument, że jest dobry lub zły, to po prostu nie działa w ten sposób.

Masz dwie opcje.

Jeden użyć prostszą konstrukcję:

if(left < right) 
    return new LeftSide<int>; 
else 
    return new RightSide<int>; 

dwa, jeśli naprawdę naprawdę chcesz użyć operatora potrójny (który jest przypadek czasami), trzeba łyżka karmić kompilator To datatypes:

Side<int>* f(int left, int right) 
{ 
    return left < right ? static_cast<Side<int>*>(new LeftSide<int>) : static_cast<Side<int>*>(new RightSide<int>);// now you're good 
} 
+1

(1) Nie można pisać konwersji definiowanych przez użytkownika pomiędzy typami wskaźników. (2) Trzeba tylko ustalić typ jednego operandu, aby działał. (3) Nawet 'static_cast' jest przesadą, ponieważ istnieje niejawna konwersja, a' static_cast' może uniemożliwić kompilatorowi ostrzeganie o uzasadnionych problemach z bezpieczeństwem typu. –

4

Myślę, że? : operator wymaga, aby 2 opcje były tego samego typu; nie, że mogą być konwertowane do tego samego typu

FYI gcc nie ten sam

error: conditional expression between distinct pointer types ‘LeftSide<int>*’ and ‘RightSide<int>*’ lacks a cast 

odlewania zarówno do Side (int) * Działa (ale prawdopodobnie wiedział, że już)

+2

Konwersja jest ok, ale jeden operand musi być wymienny na typ drugiego. Jeśli dowolny typ jest dozwolony, problem staje się trudny w ogólnym przypadku. –

+1

Myślę, że masz rację, ale to takie rozczarowanie! –

2

Chcesz zarówno gałęzie do zwrócenia Side<int>*, ale kompilator tego nie wie, typ Side<int> nie pojawia się nigdzie w tym wyrażeniu.

Ponieważ nie lubię używać obsady gdy istnieje niejawna konwersja, że ​​piszę to jako:

if (left < right) return new LeftSide<int>; 
return new RightSide<int>; 

ale jeśli chcesz użyć operatora trójskładnikowych

Side<int>* i_want_this_type; 
return (left < right) ? new LeftSide<int> : (i_want_this_type = new RightSide<int>); 

Teraz prawą gałęzią jest typ Side<int>*, lewa ręka jest wymienna na ten typ, wszystko jest w porządku (a kompilator optymalizuje dodatkową zmienną).

+0

powód downwingu? –

+0

Nie miałbym d/ved, ale domyślam się, że to dlatego, że wprowadziłeś tymczasowy - nawet jeśli jest to tymczasowy kompilator może optymalizować się do oparów. –

0

Dwa powinny być tego samego typu lub powinny być zamienne na inne.

return left < right ? (Side<int>*)new LeftSide<int> : (Side<int>*)new RightSide<int>; 
+0

Odlew w stylu C jest tutaj całkowicie przesadny. –

+0

I brutalnie brzydki i stary nieaktualny programista-hasbeen-hack-ish –

Powiązane problemy