C ++ marca como obsoleto

147

Tengo un método en una interfaz que quiero desaprobar con C ++ portátil. Cuando busqué en Google todo esto, obtuve una solución específica de Microsoft; #pragma en desuso y __declspec (en desuso) .

Una solución de segundo premio sería ifdef un MSVC y una solución GCC.
Gracias

Diederik
fuente

Respuestas:

193

En C ++ 14, puede marcar una función como obsoleta utilizando el [[deprecated]]atributo (consulte la sección 7.6.5 [dcl.attr.deprecated]).

El token de atributo deprecated se puede usar para marcar nombres y entidades cuyo uso todavía está permitido, pero se desaconseja por alguna razón.

Por ejemplo, la siguiente función fooestá en desuso:

[[deprecated]]
void foo(int);

Es posible proporcionar un mensaje que describa por qué el nombre o la entidad quedaron en desuso:

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

El mensaje debe ser un literal de cadena.

Para obtener más detalles, consulte "Marcado como obsoleto en C ++ 14" .

Joseph Mansfield
fuente
¿Se puede usar [[en desuso]] en una macro?
Daniel Ryan
2
@Zammbi Debería poder hacerlo, ya que la macro es manejada por el preprocesador antes de la compilación. [[en desuso]] debe aparecer (y dejar que el compilador muestre advertencias relacionadas) donde se evalúa la macro.
Florian Castellane el
129

Esto debería funcionar:

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

Sin embargo, encontrará problemas si un tipo de retorno de función tiene una coma en su nombre, por ejemplo, std::pair<int, int>ya que el preprocesador interpretará que pasa 2 argumentos a la macro DEPRECATED. En ese caso, debería escribir el tipo de retorno.

Editar: versión más simple (pero posiblemente menos compatible) aquí .

Michael Platings
fuente
66
En lugar de #error, sería mejor #definir la función DEPRECATED (func)
CesarB
1
mxp: La desaprobación es solo una advertencia y, por lo tanto, diría que una advertencia de que no es compatible es todo lo que necesita.
Leon Timmermans
1
Sí, iría por "#warning. Necesitas implementar DEPRECATED para este compilador", o algo así. Si eso es imposible, el portero puede #definir FUNC DEPRECADO (FUNC) y vivir sin él.
Steve Jessop
2
Desafortunadamente, no hay una forma estándar de generar una advertencia de compilación en C ++: el mensaje P #pragma tendrá que funcionar.
Michael Platings
3
La sintaxis de atributo de gcc permite que el atributo esté en los mismos lugares que __declspec(deprecated)ahora, por lo que la macro se puede simplificar.
bames53
57

Aquí hay una versión simplificada de mi respuesta 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);

Ver también:

Michael Platings
fuente
17
¿Cómo haces [[deprecate]]tus macros en desuso? :-)
graham.reeds
3
No puedo ver ninguna diferencia significativa entre esas dos respuestas. ¿Por qué lo publicaste por segunda vez?
Tomáš Zato - Restablece a Mónica el
44
No tiene que ajustarlo alrededor de la función para que sea en DEPRECATED void foo(...);lugar deDEPRECATED(void foo(...));
dshepherd
12
Debería haber editado su respuesta de 2008 en lugar de publicar una nueva.
Yakov Galka
44
Esto puede no ser tan ampliamente compatible como mi otra respuesta, por lo tanto, agregué esto por separado.
Michael Platings
22

En GCC puede declarar su función con el atributo en desuso de esta manera:

void myfunc() __attribute__ ((deprecated));

Esto activará una advertencia en tiempo de compilación cuando esa función se use en un archivo .c.

Puede encontrar más información en "Pragmas de diagnóstico" en http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html

Terje Mikal
fuente
8

Aquí hay una respuesta más completa para 2018.

En la actualidad, muchas herramientas le permiten no solo marcar algo como obsoleto, sino también enviar un mensaje. Esto le permite informar a las personas cuando algo ha quedado en desuso, y tal vez señalarles hacia un reemplazo.

Todavía hay mucha variedad en el soporte del compilador:

  • C ++ 14 soporta [[deprecated]]/ [[deprecated(message)]].
  • __attribute__((deprecated)) es compatible con GCC 4.0+ y ARM 4.1+
  • __attribute__((deprecated))y __attribute__((deprecated(message)))es compatible con:
    • GCC 4.5+
    • Varios compiladores que se hacen pasar por GCC 4.5+ (configurando __GNUC__/ __GNUC_MINOR__/ __GNUC_PATCHLEVEL__)
    • El compilador Intel C / C ++ se remonta al menos a 16 (no puede confiar __GNUC__/ __GNUC_MINOR__simplemente lo configuran a cualquier versión de GCC instalada)
    • BRAZO 5.6+
  • MSVC admite __declspec(deprecated)desde 13.10 (Visual Studio 2003)
  • MSVC admite __declspec(deprecated(message))desde 14.0 (Visual Studio 2005)

También puede usar [[gnu::deprecated]]en versiones recientes de clang en C ++ 11, basado en __has_cpp_attribute(gnu::deprecated).

Tengo algunas macros en Hedley para manejar todo esto automáticamente, que mantengo actualizado, pero la versión actual (v2) se ve así:

#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

Lo dejaré como un ejercicio para descubrir cómo deshacerse de las macros *_VERSION_CHECKy *_HAS_ATTRIBUTEsi no desea usar Hedley (escribí Hedley en gran parte para no tener que pensar en eso regularmente).

Si usa GLib, puede usar las macros G_DEPRECATEDy G_DEPRECATED_FOR. No son tan robustos como los de Hedley, pero si ya usa GLib no hay nada que agregar.

nemequ
fuente
4

Al tratar con proyectos portátiles, es casi inevitable que en algún momento necesite una sección de alternativas preprocesadas para una gama de plataformas. #ifdef esto #ifdef eso y así sucesivamente.

En dicha sección, podría definir condicionalmente una forma de desaprobar los símbolos. Por lo general, prefiero definir una macro de "advertencia" ya que la mayoría de las cadenas de herramientas admiten advertencias de compilación personalizadas. Luego, puede continuar con una macro de advertencia específica para desaprobación, etc. Para las plataformas que admiten métodos de desaprobación específicos, puede usar eso en lugar de advertencias.

Sharkin
fuente
1

Para Intel Compiler v19.0, use esto como __INTEL_COMPILERevalúa para 1900:

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

Funciona para los siguientes niveles de idioma:

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

Intel Compiler tiene lo que parece un error, ya que no admite el [[deprecated]]atributo en ciertos elementos del lenguaje que todos los demás compiladores. Por ejemplo, compile v6.0.0 de la biblioteca (notablemente excelente) {fmtlib / fmt} en GitHub con Intel Compiler v19.0. Se romperá Luego vea la solución en la confirmación de GitHub .

Aplazamiento de pago
fuente
Esto es incorrecto; Los atributos de C ++ no funcionan en modo C en ICC. Ejemplo . __attribute__((deprecated)), OTOH, funciona en C y C ++ desde al menos ICC 13.0, probablemente mucho más (Intel tiende a no documentar este tipo de cosas, así que no puedo estar seguro).
nemequ