Szablony C ++ są znane z generowania długich, nieczytelnych komunikatów o błędach. Mam ogólne pojęcie, dlaczego komunikaty o błędach szablonów w C ++ są tak złe. Zasadniczo problem polega na tym, że błąd nie jest wyzwalany, dopóki kompilator nie napotka składni, która nie jest obsługiwana przez określony typ w szablonie. Na przykład:
template <class T>
void dosomething(T& x) { x += 5; }
Jeśli T
nie obsługuje +=
operatora, kompilator wygeneruje komunikat o błędzie. A jeśli dzieje się to gdzieś głęboko w bibliotece, komunikat o błędzie może mieć tysiące linii.
Ale szablony C ++ są w zasadzie tylko mechanizmem do pisania kaczego w czasie kompilacji. Błąd szablonu C ++ jest koncepcyjnie bardzo podobny do błędu typu środowiska wykonawczego, który może wystąpić w dynamicznym języku, takim jak Python. Rozważmy na przykład następujący kod Python:
def dosomething(x):
x.foo()
Tutaj, jeśli x
nie ma foo()
metody, interpreter Pythona zgłasza wyjątek i wyświetla ślad stosu wraz z dość wyraźnym komunikatem o błędzie wskazującym problem. Nawet jeśli błąd nie zostanie wyzwolony, dopóki interpreter nie znajdzie się głęboko w jakiejś funkcji bibliotecznej, komunikat o błędzie środowiska wykonawczego nadal nie jest tak zły jak nieczytelne wymioty wyrzucane przez typowy kompilator C ++. Dlaczego więc kompilator C ++ nie może lepiej wyjaśnić, co poszło nie tak? Dlaczego niektóre komunikaty o błędach szablonu C ++ dosłownie powodują przewijanie okna konsoli przez ponad 5 sekund?
źródło
clang++
mrugnięcie, mrugnięcie).Odpowiedzi:
Komunikaty o błędach szablonu mogą być znane, ale w żadnym wypadku nie zawsze są długie i nieczytelne. W takim przypadku cały komunikat o błędzie (z gcc) to:
Podobnie jak w przykładzie w Pythonie, otrzymujesz „ślad stosu” punktów tworzenia szablonów i jasny komunikat o błędzie wskazujący na problem.
Czasami komunikaty o błędach związane z szablonami mogą być znacznie dłuższe z różnych powodów:
Główną różnicą w stosunku do Pythona jest statyczny system typów, co prowadzi do konieczności dołączania (czasem długich) nazw typów w komunikacie o błędzie. Bez nich czasami bardzo trudno zdiagnozować, dlaczego nie udało się rozwiązać problemu przeciążenia. Dzięki nim Twoim wyzwaniem nie jest już odgadnięcie, gdzie jest problem, ale rozszyfrowanie hieroglifów, które mówią ci, gdzie to jest.
Ponadto sprawdzenie w czasie wykonywania oznacza, że program zatrzyma się przy pierwszym napotkanym błędzie, wyświetlając tylko jeden komunikat. Kompilator może wyświetlać wszystkie napotkane błędy, dopóki się nie poddaje; przynajmniej w C ++ nie powinien kończyć się na pierwszym błędzie w pliku, ponieważ może to być konsekwencją późniejszego błędu.
źródło
Kilka oczywistych powodów to:
Nie jest to wyczerpujące, ale masz ogólny pomysł. Nawet jeśli nie jest to łatwe, większość można wyleczyć. Przez lata mówiłem ludziom, aby otrzymywali kopię Comeau C ++ do regularnego użytku; Prawdopodobnie raz zaoszczędziłem na jednym komunikacie o błędzie, aby zapłacić za kompilator. Teraz Clang dochodzi do tego samego punktu (i jest jeszcze tańszy).
Zakończę ogólną obserwacją, która brzmi jak żart, ale tak naprawdę nie jest. Przez większość czasu prawdziwym zadaniem kompilatora jest przekształcanie kodu źródłowego w komunikaty o błędach. Najwyższy czas, aby dostawcy skoncentrowali się na wykonywaniu tej pracy nieco lepiej - chociaż otwarcie przyznam, że kiedy pisałem kompilatory, miałem silną tendencję do traktowania jej jako drugorzędnej (w najlepszym wypadku), aw niektórych przypadkach prawie ją ignorowałem całkowicie.
źródło
Prosta odpowiedź brzmi, ponieważ Python został zaprojektowany w taki sposób, podczas gdy wiele rzeczy związanych z szablonami powstało przez przypadek. Na przykład nigdy nie zamierzano stać się systemem kompletnym dla Turinga. A jeśli nie możesz celowo zaplanować i uzasadnić tego, co dzieje się, gdy twój system działa , dlaczego ktoś miałby oczekiwać ostrożnego, przemyślanego planowania tego, co dzieje się, gdy coś pójdzie nie tak?
Ponadto, jak wskazałeś, interpreter języka Python może ci znacznie ułatwić, wyświetlając ślad stosu, ponieważ interpretuje kod języka Python. Jeśli kompilator C ++ napotka błąd szablonu i poda ślad stosu, byłoby to tak samo nieprzydatne jak „szablon wymiotuje”, prawda?
źródło