Jak ustalić, które pliki nagłówkowe należy uwzględnić?

13

Powiedz, że mam poniższy (bardzo prosty) kod.

#include <iostream>
int main() {
    std::cout << std::stoi("12");
}

Kompiluje to dobrze zarówno na g ++, jak i clang; jednak nie można go skompilować na MSVC z następującym błędem:

błąd C2039: „stoi”: nie jest członkiem „std”

błąd C3861: „stoi”: nie znaleziono identyfikatora

Wiem, że std::stoijest to część <string>nagłówka, który prawdopodobnie obejmuje dwa poprzednie kompilatory, <iostream>a drugi nie. Zgodnie ze standardem C ++ [res.on.headers]

Nagłówek C ++ może zawierać inne nagłówki C ++.

Co dla mnie w zasadzie mówi, że wszystkie trzy kompilatory są poprawne.

Kwestia ta pojawiła się, gdy jeden z moich studentów przesłał prace, które TA oznaczyła jako niekompilujące; Oczywiście poszedłem i to naprawiłem. Chciałbym jednak zapobiec takim incydentom w przyszłości. Czy istnieje sposób na określenie, które pliki nagłówkowe powinny zostać uwzględnione, bez kompilacji na trzech różnych kompilatorach, które należy sprawdzać za każdym razem?

Jedynym sposobem, jaki mogę wymyślić, jest zapewnienie, aby dla każdego stdwywołania funkcji istniało odpowiednie uwzględnienie; ale jeśli masz istniejący kod, który ma tysiące linii, przeszukiwanie go może być uciążliwe. Czy istnieje łatwiejszy / lepszy sposób zapewnienia zgodności między kompilatorami?

Przykład z trzema kompilatorami: https://godbolt.org/z/kJhS6U

ChrisMM
źródło
6
Jeśli pamiętasz, że std::stoijest to do obsługi ciągów, możesz zgadywać, że <string>byłby to dobry nagłówek do włączenia. Lub możesz wyszukać dobre referencje, które ci powiedzą. I zalecam, aby zawsze jawnie dołączać pliki nagłówkowe, abyś nie musiał polegać na nieprzenośnych specyficznych zachowaniach związanych z implementacją.
Jakiś programista koleś
3
Najlepszym sposobem jest przejście do preferencji przed przejściem na inną platformę. Mają tam dość szczegółowe rzeczy.
Siddharth
1
Dołącz odpowiedni nagłówek w momencie pisania kodu. To znaczy. w momencie pisania kodu, który zawiera, std::stoinatychmiast upewniasz się, że również #include <string>jest obecny.
Sander De Dycker
3
W ogólnym przypadku jest to trudny problem . Jednak gdy mówimy o brakujących standardowych bibliotekach, normalnym sposobem byłoby rzeczywiście sprawdzenie wszystkich użytych wywołań / typów funkcji.
Max Langhof
1
@ skratchi.at, uczniom mówi się, że mogą korzystać z dowolnego kompilatora, o ile chcą, o ile ich kod jest zgodny ze standardami. Po 4 latach po raz pierwszy był to problem.
ChrisMM

Odpowiedzi:

14

Czy istnieje łatwiejszy / lepszy sposób zapewnienia zgodności między kompilatorami?

To zawsze będzie trochę uciążliwe, jeśli masz ogromną bazę kodu i do tej pory tego nie robiłeś, ale kiedy już skończysz poprawianie załączników, możesz zastosować się do prostej procedury:

Kiedy piszesz nowy kod, który używa standardowej funkcji, takiej jak std::stoi Podłącz tę nazwę do Google, przejdź do artykułu cppreference.com, a następnie spójrz na górę, aby zobaczyć, w którym nagłówku jest zdefiniowany.

Następnie dołącz to, jeśli jeszcze nie zostało uwzględnione. Zadanie wykonane!

(Możesz do tego użyć standardu, ale nie jest to tak łatwo dostępne).

Nie ulegaj pokusie, aby pozbyć się wszystkiego na rzecz tanich, niemożliwych do przenoszenia hacków takich jak <bits/stdc++.h>!


tl; dr: dokumentacja

Lekkość Wyścigi na orbicie
źródło
3
Szczerze mówiąc, kiedy już skutecznie zapamiętałeś je wszystkie i nie musisz już więcej ich szukać, wydaje się to całkiem sprytne
Lekkość ściga się na orbicie
5
@JosephWood: Jeśli nie wiesz, który nagłówek dana funkcja jest na pamięć, istnieje szansa, że powinieneś sprawdzić tę funkcję, aby jeszcze raz sprawdzić swoje założenia na niej, więc ustalenie, do którego nagłówka należy, nie wymaga nawet dodatkowych czas.
DevSolar
1
Podobnie jak @JosephWood, miałem również nadzieję, że osoby z większym doświadczeniem będą miały lepszy sposób. Wiem, które nagłówki należy uwzględnić w przypadku większości funkcji STL, ale miałem nadzieję, że istnieje łatwiejszy sposób na nauczenie studentów niż wyszukiwanie każdej funkcji: P
ChrisMM
1
@ChrisMM istnieją narzędzia takie jak „ włącz to, czego używasz” . Nie można zagwarantować ich poprawności (i czasem praca fizyczna jest konieczna), ale wcale nie jest taka zła.
dziwaczny
4
@ChrisMM Nauczanie uczniów, jak korzystać z dokumentacji, jest niezwykle ważne . Tysiące przesyłają codziennie tę stronę bez ziemskiego pomysłu, że powinni to zrobić. Korzystanie z dokumentacji jest łatwiejszym / lepszym sposobem.
Wyścigi lekkości na orbicie
-1

Oprócz przeglądania dokumentacji i robienia tego ręcznie (bolesne i czasochłonne) możesz skorzystać z niektórych narzędzi, które mogą to zrobić za Ciebie.

Możesz użyć ReSharper w Visual Studio, który jest w stanie organizować import (w rzeczywistości VS bez ReSharper nie jest zbyt użyteczny). W przypadku braku dołączenia zaleca się jego dodanie, a jeśli jest przestarzała, linia z włączeniem jest wyświetlana w bardziej jasnych kolorach.

Lub możesz użyć CLion (dostępny na wszystkie platformy), który również ma tę funkcję (w rzeczywistości jest to ta sama produkcja JetBrains).

Istnieje również narzędzie o nazwie włącz to, czego użyłeś , ale jego celem jest skorzystanie z deklaracji forward, nigdy tego nie użyłem (osobiście - mój kolega z zespołu zrobił to dla naszego projektu).

Marek R.
źródło
clion nie włącza automatycznie poprawnego nagłówka, gdy inny nagłówek jest już dołączony, jeśli działa (tzn. nie zasugeruje tutaj ciągu, jeśli iostream jest już uwzględniony) IIRC
RiaD