Oznacz w C ++ jako przestarzałe

147

Mam metodę w interfejsie, którą chcę wycofać z przenośnego C ++. Kiedy szukałem tego w Google, otrzymałem tylko rozwiązanie specyficzne dla firmy Microsoft; #pragma przestarzałe i __declspec (przestarzałe) .

Drugim rozwiązaniem byłoby zdefiniowanie MSVC i GCC.
Dzięki

Diederik
źródło

Odpowiedzi:

193

W C ++ 14 możesz oznaczyć funkcję jako przestarzałą za pomocą [[deprecated]]atrybutu (zobacz sekcję 7.6.5 [dcl.attr.deprecated]).

Atrybut Token deprecated może być używany do nazw znaków i podmiotów, których stosowanie jest nadal dozwolone, ale nie jest zalecane z jakiegoś powodu.

Na przykład następująca funkcja foojest przestarzała:

[[deprecated]]
void foo(int);

Możliwe jest podanie komunikatu opisującego, dlaczego nazwa lub podmiot zostały wycofane:

[[deprecated("Replaced by bar, which has an improved interface")]]
void foo(int);

Wiadomość musi być ciągiem znaków.

Aby uzyskać więcej informacji, zobacz „Oznaczanie jako przestarzałe w C ++ 14” .

Joseph Mansfield
źródło
Czy możesz użyć [[przestarzałe]] w makrze?
Daniel Ryan,
2
@Zammbi Powinieneś być w stanie, ponieważ makro jest obsługiwane przez preprocesor przed kompilacją. [[przestarzałe]] powinno pojawić się (i pozwolić kompilatorowi na wyświetlenie powiązanych ostrzeżeń) w miejscu oceny makra.
Florian Castellane
129

To powinno załatwić sprawę:

#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif

...

//don't use me any more
DEPRECATED(void OldFunc(int a, float b));

//use me instead
void NewFunc(int a, double b);

Jednak napotkasz problemy, jeśli typ zwracany przez funkcję ma w nazwie przecinki, np. std::pair<int, int>Ponieważ zostanie to zinterpretowane przez preprocesor jako przekazanie 2 argumentów do makra DEPRECATED. W takim przypadku musiałbyś wpisać zwracany typ.

Edycja: prostsza (ale prawdopodobnie mniej kompatybilna) wersja tutaj .

Michael Platings
źródło
6
Zamiast #error lepiej byłoby #define DEPRECATED (func) func
CesarB
1
mxp: Wycofanie jest tylko ostrzeżeniem, dlatego powiedziałbym, że wystarczy ostrzeżenie, że nie jest obsługiwany.
Leon Timmermans
1
Tak, wybrałbym „#warning Musisz zaimplementować DEPRECATED dla tego kompilatora” lub coś takiego. Jeśli to niemożliwe, portier może #definiować DEPRECATED (FUNC) FUNC i żyć bez niej.
Steve Jessop,
2
Niestety nie ma standardowego sposobu na wyświetlenie ostrzeżenia kompilacji w C ++: wiadomość P #pragma będzie musiała zrobić.
Michael Platings
3
Składnia atrybutu gcc pozwala na umieszczenie atrybutu w tych samych miejscach, co __declspec(deprecated)teraz, więc makro można uprościć.
bames53
57

Oto uproszczona wersja mojej odpowiedzi z 2008 roku :

#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED
#endif

//...

//don't use me any more
DEPRECATED void OldFunc(int a, float b);

//use me instead
void NewFunc(int a, double b);

Zobacz też:

Michael Platings
źródło
17
Jak oceniasz [[deprecate]]wycofane makra? :-)
graham.reeds
3
Nie widzę żadnej znaczącej różnicy między tymi dwoma odpowiedziami. Dlaczego opublikowałeś to po raz drugi?
Tomáš Zato - Przywróć Monikę
4
Nie musisz owijać tego wokół funkcji, więc jest DEPRECATED void foo(...);zamiastDEPRECATED(void foo(...));
dshepherd
12
Powinieneś był edytować swoją odpowiedź z 2008 roku, zamiast publikować nową.
Yakov Galka
4
Może to nie być tak szeroko zgodne, jak moja inna odpowiedź, dlatego dodałem ją osobno.
Michael Platings
22

W GCC możesz zadeklarować swoją funkcję z atrybutem przestarzałym w następujący sposób:

void myfunc() __attribute__ ((deprecated));

Spowoduje to wyświetlenie ostrzeżenia w czasie kompilacji, gdy ta funkcja zostanie użyta w pliku .c.

Więcej informacji można znaleźć w sekcji „Pragmy diagnostyczne” pod adresem http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html

Terje Mikal
źródło
8

Oto pełniejsza odpowiedź na rok 2018.

Obecnie wiele narzędzi pozwala nie tylko oznaczyć coś jako przestarzałe, ale także przekazać wiadomość. Dzięki temu możesz poinformować ludzi, że coś zostało wycofane, i może wskazać im zamianę.

Wciąż istnieje duża różnorodność w obsłudze kompilatorów:

  • C ++ 14 obsługuje [[deprecated]]/ [[deprecated(message)]].
  • __attribute__((deprecated)) jest obsługiwany przez GCC 4.0+ i ARM 4.1+
  • __attribute__((deprecated))i __attribute__((deprecated(message)))jest obsługiwany przez:
    • GCC 4.5+
    • Kilka kompilatorów podszywających się pod GCC 4.5+ (przez ustawienie __GNUC__/ __GNUC_MINOR__/ __GNUC_PATCHLEVEL__)
    • Kompilator Intel C / C ++ wraca do co najmniej 16 (nie możesz ufać __GNUC__/ __GNUC_MINOR__, po prostu ustawili go na dowolną wersję GCC)
    • ARM 5.6+
  • MSVC obsługuje __declspec(deprecated)od 13.10 (Visual Studio 2003)
  • Obsługa MSVC __declspec(deprecated(message))od 14,0 (Visual Studio 2005)

Możesz również użyć [[gnu::deprecated]]w najnowszych wersjach clang w C ++ 11, opartych na __has_cpp_attribute(gnu::deprecated).

Mam kilka makr w Hedley do obsługi tego wszystkiego automatycznie, które aktualizuję, ale obecna wersja (v2) wygląda tak:

#if defined(__cplusplus) && (__cplusplus >= 201402L)
#  define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]]
#  define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]]
#elif \
  HEDLEY_GCC_HAS_EXTENSION(attribute_deprecated_with_message,4,5,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_ARM_VERSION_CHECK(5,6,0)
#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
#elif \
  HEDLEY_GCC_HAS_ATTRIBUTE(deprcated,4,0,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0)
#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0)
#  define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_DEPRECATED(since) _declspec(deprecated)
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
#else
#  define HEDLEY_DEPRECATED(since)
#  define HEDLEY_DEPRECATED_FOR(since, replacement)
#endif

Zostawię to jako ćwiczenie, aby dowiedzieć się, jak pozbyć się makr *_VERSION_CHECKi, *_HAS_ATTRIBUTEjeśli nie chcesz używać Hedley (napisałem Hedley w dużej mierze, więc nie musiałem o tym regularnie myśleć).

Jeśli używasz GLib, możesz używać makr G_DEPRECATEDi G_DEPRECATED_FOR. Nie są tak wytrzymałe jak te firmy Hedley, ale jeśli już używasz GLib, nie ma nic do dodania.

nemequ
źródło
4

W przypadku projektów przenośnych jest prawie nieuniknione, że w pewnym momencie będziesz potrzebować sekcji wstępnie przetworzonych alternatyw dla szeregu platform. #ifdef to #ifdef tamto i tak dalej.

W takiej sekcji można bardzo dobrze warunkowo zdefiniować sposób wycofywania symboli. Preferuję zwykle zdefiniowanie makra „ostrzegawczego”, ponieważ większość łańcuchów narzędzi obsługuje niestandardowe ostrzeżenia kompilatora. Następnie możesz przejść do określonego makra ostrzegawczego, który oznacza dezaktualizację itp. W przypadku platform obsługujących dedykowane metody wycofywania możesz użyć tego zamiast ostrzeżeń.

sharkin
źródło
1

W przypadku kompilatora Intel Compiler w wersji 19.0 użyj tego w __INTEL_COMPILERcelu 1900:

#  if defined(__INTEL_COMPILER)
#    define DEPRECATED [[deprecated]]
#  endif

Działa na następujących poziomach językowych:

  • Obsługa C ++ 17 (/ Qstd = c ++ 17)
  • Obsługa C ++ 14 (/ Qstd = c ++ 14)
  • Obsługa C ++ 11 (/ Qstd = c ++ 11)
  • Obsługa C11 (/ Qstd = c11)
  • Obsługa C99 (/ Qstd = c99)

Kompilator Intel ma coś, co wygląda na błąd polegający na tym, że nie obsługuje [[deprecated]]atrybutu w niektórych elementach języka, tak jak robią to wszystkie inne kompilatory. Na przykład skompiluj wersję 6.0.0 (zadziwiająco wspaniałej) biblioteki {fmtlib / fmt} w serwisie GitHub za pomocą kompilatora Intel Compiler 19.0. To się zepsuje. Następnie zobacz poprawkę w zatwierdzeniu GitHub .

Contango
źródło
To jest niepoprawne; Atrybuty C ++ nie działają w trybie C w ICC. Przykład . __attribute__((deprecated)), OTOH, działa w C i C ++, cofając się co najmniej do ICC 13.0, prawdopodobnie znacznie dalej (Intel raczej nie dokumentuje tego typu rzeczy, więc nie jestem pewien).
nemequ