2017-08-25 9 views
6

Mam pytanie dotyczące szablonów C++. Następujące kody są uszkodzone.segfault w szablonach C++

template <typename T1, typename T2> 
inline T1 const& max(T1 const &a, T2 const &b) { 
    return a < b ? b : a; 
} 
int main() { 
    std::cout << max(4.9, 4) << std::endl; 
} 

jednak usunąć & i robi słusznie.

template<typename T1, typename T2> 
inline T1 const max(T1 const &a, T2 const &b) { 
    return a < b ? b : a; 
} 
int main() { 
    std::cout << max(4.9, 4) << std::endl; 
} 

Co więcej, po prostu użyj T zamiast T1 i T2 i działa dobrze.

template<typename T> 
inline T const& max(T const &a, T const &b) { 
    return a < b ? b : a; 
} 

int main() { 
    std::cout << max(4, 5) << std::endl; 
} 

Co ja tu robię źle?

+0

Proszę wymienić kompilator, w tym numer wersji, którego używasz. Jeśli jest to GCC, czy skompilowałeś go z '-Wall'? Może być ostrzeżenie, które ignorujesz, które powoduje niezdefiniowane zachowanie. –

+0

Kompilator powinien informować, że wywołanie max() zwraca odwołanie do tymczasowego. – tristan

+1

Pierwsze dwa fragmenty kodu są identyczne? – asimes

Odpowiedz

10

Powinieneś zawsze kompilować z włączonymi ostrzeżeniami, zobacz https://wandbox.org/permlink/KkhFOJw6QNJ7rv7J. Gdybyś miał włączone flagi ostrzegawcze, kompilator pomógłby ci i powiedziałby ci, co robisz źle.

To, co się tutaj dzieje, to promocja (patrz Return type of '?:' (ternary conditional operator)), wykonywane jest potrójne wyrażenie na int i double. Powoduje to tymczasowe awansowanie double. I zwracanie odniesienia do tymczasowego i odniesienie do tego, że po funkcji, w której jej czas życia jest związany zwrotami, jest niezdefiniowane zachowanie.

1

W dwóch pierwszych zwraca się odwołanie do tymczasowego.

Dlaczego? Cóż, twoja funkcja zwraca typ T1, ale będziesz musiał przekonwertować jeden z wysyłanych typów. Konwersja tworzy tymczasowy odpowiedni typ. Potem go zwrócisz.

Od czasu tymczasowych matryc, zwrócone odniesienie jest powiązane z martwym przedmiotem.

Już znalazłeś poprawkę. Nie zwracasz referencji, albo przyjmujesz parametry tego samego typu.

Jeśli spojrzeć na standardową realizację, wybrał drugie rozwiązanie: pobranie parametrów tego samego typu.