Marquer C ++ comme obsolète

147

J'ai une méthode dans une interface que je souhaite déprécier avec le C ++ portable. Lorsque j'ai recherché cela sur Google, tout ce que j'ai obtenu était une solution spécifique à Microsoft; #pragma obsolète et __declspec (obsolète) .

Une deuxième solution serait de définir un MSVC et une solution GCC.
Merci

Diederik
la source

Réponses:

193

En C ++ 14, vous pouvez marquer une fonction comme obsolète à l'aide de l' [[deprecated]]attribut (voir section 7.6.5 [dcl.attr.deprecated]).

Le jeton d'attribut deprecated peut être utilisé pour marquer les noms et les entités dont l'utilisation est toujours autorisée, mais est déconseillée pour une raison quelconque.

Par exemple, la fonction suivante fooest obsolète:

[[deprecated]]
void foo(int);

Il est possible de fournir un message décrivant pourquoi le nom ou l'entité est obsolète:

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

Le message doit être une chaîne littérale.

Pour plus de détails, consultez «Marquage comme obsolète dans C ++ 14» .

Joseph Mansfield
la source
Pouvez-vous utiliser [[obsolète]] dans une macro?
Daniel Ryan
2
@Zammbi Vous devriez pouvoir le faire, car la macro est gérée par le préprocesseur avant la compilation. [[obsolète]] doit apparaître (et laisser le compilateur afficher les avertissements liés) là où la macro est évaluée.
Florian Castellane
129

Cela devrait faire l'affaire:

#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);

Cependant, vous rencontrerez des problèmes si un type de retour de fonction a une virgule dans son nom, par exemple std::pair<int, int> car cela sera interprété par le préprocesseur comme passant 2 arguments à la macro DEPRECATED. Dans ce cas, vous devrez taperef le type de retour.

Edit: version plus simple (mais peut-être moins largement compatible) ici .

Michael Platings
la source
6
Au lieu de #error, il serait préférable de #define DEPRECATED (func) func
CesarB
1
mxp: La dépréciation n'est qu'un avertissement, et je dirais donc qu'un avertissement indiquant qu'il n'est pas pris en charge est tout ce dont vous avez besoin.
Leon Timmermans
1
Oui, j'irais pour "#warning Vous devez implémenter DEPRECATED pour ce compilateur", ou quelque chose du genre. Si c'est impossible, le portier peut #define DEPRECATED (FUNC) FUNC et vivre sans.
Steve Jessop
2
Malheureusement, il n'y a pas de moyen standard de générer un avertissement de compilation en C ++: le message P #pragma devra faire.
Michael Platings
3
La syntaxe d'attribut de gcc permet à l'attribut d'être aux mêmes endroits que __declspec(deprecated)maintenant, de sorte que la macro peut être simplifiée.
bames53
57

Voici une version simplifiée de ma réponse de 2008 :

#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);

Voir également:

Michael Platings
la source
17
Comment avez-vous [[deprecate]]vos macros obsolètes? :-)
graham.reeds
3
Je ne vois aucune différence significative entre ces deux réponses. Pourquoi l'avez-vous posté une deuxième fois?
Tomáš Zato - Réintégrer Monica
4
Vous n'avez pas à l'enrouler autour de la fonction, donc c'est à la DEPRECATED void foo(...);place deDEPRECATED(void foo(...));
dshepherd
12
Vous devriez avoir modifié votre réponse de 2008 plutôt que d'en publier une nouvelle.
Yakov Galka
4
Cela n'est peut-être pas aussi largement compatible que mon autre réponse, c'est pourquoi j'ai ajouté cela séparément.
Michael Platings
22

Dans GCC, vous pouvez déclarer votre fonction avec l'attribut obsolète comme ceci:

void myfunc() __attribute__ ((deprecated));

Cela déclenchera un avertissement lors de la compilation lorsque cette fonction est utilisée dans un fichier .c.

Vous pouvez trouver plus d'informations sous "Pragmas de diagnostic" à http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html

Terje Mikal
la source
8

Voici une réponse plus complète pour 2018.

De nos jours, de nombreux outils vous permettent non seulement de marquer quelque chose comme obsolète, mais également de fournir un message. Cela vous permet de dire aux gens quand quelque chose est obsolète et peut-être de les diriger vers un remplacement.

Il y a encore beaucoup de variété dans le support du compilateur:

  • C ++ 14 prend en charge [[deprecated]]/ [[deprecated(message)]].
  • __attribute__((deprecated)) est pris en charge par GCC 4.0+ et ARM 4.1+
  • __attribute__((deprecated)) et __attribute__((deprecated(message))) est pris en charge pour:
    • GCC 4.5+
    • Plusieurs compilateurs qui se font passer pour GCC 4.5+ (en définissant __GNUC__/ __GNUC_MINOR__/__GNUC_PATCHLEVEL__ )
    • Compilateur Intel C / C ++ remontant à au moins 16 (vous ne pouvez pas faire confiance à __GNUC__/ __GNUC_MINOR__, ils le définissent simplement sur la version de GCC installée)
    • ARM 5.6+
  • MSVC prend en charge __declspec(deprecated)depuis 13.10 (Visual Studio 2003)
  • MSVC prend en charge __declspec(deprecated(message))depuis 14.0 (Visual Studio 2005)

Vous pouvez également utiliser [[gnu::deprecated]]dans les versions récentes de clang en C ++ 11, basé sur __has_cpp_attribute(gnu::deprecated).

J'ai quelques macros dans Hedley pour gérer tout cela automatiquement que je tiens à jour, mais la version actuelle (v2) ressemble à ceci:

#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

Je vais laisser comme un exercice pour savoir comment se débarrasser des *_VERSION_CHECKet*_HAS_ATTRIBUTE macros si vous ne voulez pas utiliser Hedley (j'ai écrit Hedley en grande partie pour ne pas avoir à y penser régulièrement).

Si vous utilisez GLib, vous pouvez utiliser les macros G_DEPRECATEDet G_DEPRECATED_FOR. Ils ne sont pas aussi robustes que ceux de Hedley, mais si vous utilisez déjà GLib, il n'y a rien à ajouter.

nemequ
la source
4

Gérer des projets portables, il est presque inévitable que vous ayez besoin à un moment donné d'une section d'alternatives prétraitées pour une gamme de plates-formes. #ifdef ceci #ifdef cela et ainsi de suite.

Dans une telle section, vous pourriez très bien définir conditionnellement un moyen de désapprouver les symboles. Ma préférence est généralement de définir une macro "avertissement" car la plupart des chaînes d'outils prennent en charge les avertissements personnalisés du compilateur. Ensuite, vous pouvez continuer avec une macro d'avertissement spécifique pour la dépréciation, etc. Pour les plates-formes prenant en charge des méthodes dépréciées dédiées, vous pouvez l'utiliser à la place des avertissements.

sharkin
la source
1

Pour Intel Compiler v19.0, utilisez ceci comme __INTEL_COMPILERévalue pour 1900:

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

Fonctionne pour les niveaux de langue suivants:

  • Prise en charge de C ++ 17 (/ Qstd = c ++ 17)
  • Prise en charge de C ++ 14 (/ Qstd = c ++ 14)
  • Prise en charge de C ++ 11 (/ Qstd = c ++ 11)
  • Prise en charge de C11 (/ Qstd = c11)
  • Prise en charge de C99 (/ Qstd = c99)

Le compilateur Intel a ce qui semble être un bogue en ce sens qu'il ne prend pas en charge l' [[deprecated]]attribut sur certains éléments de langage comme le font tous les autres compilateurs. Par exemple, compilez la v6.0.0 de la (remarquablement superbe) bibliothèque {fmtlib / fmt} sur GitHub avec Intel Compiler v19.0. Ça va casser. Ensuite, voyez le correctif dans le commit GitHub .

Contango
la source
Ceci est une erreur; Les attributs C ++ ne fonctionnent pas en mode C sur ICC. Exemple . __attribute__((deprecated)), OTOH, fonctionne en C et C ++ depuis au moins ICC 13.0, probablement beaucoup plus loin (Intel a tendance à ne pas documenter ce type de choses donc je ne peux pas être sûr).
nemequ